Skip to content

feat: Glossaries #3003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 138 commits into from
Jun 5, 2025
Merged

feat: Glossaries #3003

merged 138 commits into from
Jun 5, 2025

Conversation

Anty0
Copy link
Collaborator

@Anty0 Anty0 commented Mar 21, 2025

Implements #2969 and #1418
Requires https://github.com/tolgee/translator/pull/32 to be deployed.
Expects these links to be valid documentation links:

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive Glossary feature for organizations, including management of glossaries, terms, translations, and term highlights.
    • Added REST API endpoints for creating, updating, deleting, and retrieving glossaries and glossary terms, with support for translations and project assignments.
    • Implemented listing of languages used by organization projects and glossaries, including base languages.
    • Added UI components and dialogs for glossary and glossary term management, including batch operations and language selection.
    • Integrated glossary term highlighting in translation tools to assist translators and reviewers.
    • Enhanced search and filtering capabilities across glossary terms and languages.
    • Added extensive end-to-end Cypress tests covering glossary creation, editing, deletion, navigation, highlighting, and permissions.
    • Introduced feature flag support for the Glossary feature.
  • Bug Fixes

    • Improved API validation and error handling for glossary-related operations.
  • Documentation

    • Updated contributor guidelines with enhanced testing and translation key instructions.
  • Tests

    • Added comprehensive automated tests for glossary APIs, permissions, language endpoints, and UI components ensuring role-based access control and feature robustness.
  • Chores

    • Refined codebase with annotation updates, suppression of static analysis warnings, and minor refactoring for maintainability.
    • Updated API schema with glossary-related endpoints and models.
    • Improved type safety and component abstractions in frontend code.
    • Added React StrictMode wrapping for the app root.
    • Enhanced UI components with accessibility and styling improvements.

@Anty0 Anty0 force-pushed the jirikuchynka/glossaries branch 2 times, most recently from b6ac50b to 1bfd767 Compare March 27, 2025 15:21
Copy link
Contributor

coderabbitai bot commented Apr 1, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update introduces a comprehensive glossary feature, including backend entities, repositories, services, controllers, DTOs, HATEOAS models, and extensive test coverage. New endpoints allow organizations to manage glossaries, terms, and translations, with role-based permissions and feature toggling. Supporting infrastructure (database schema, utility functions, OpenAPI docs) and machine translation integration are also included.

Changes

Files/Group Change Summary
.junie/guidelines.md Expanded and clarified contribution/testing/translation guidelines.
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/organization/OrganizationLanguageController.kt
backend/api/src/main/kotlin/io/tolgee/hateoas/language/OrganizationLanguageModel.kt
backend/api/src/main/kotlin/io/tolgee/hateoas/language/OrganizationLanguageModelAssembler.kt
backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/OrganizationLanguageDto.kt
backend/data/src/main/kotlin/io/tolgee/dtos/request/language/LanguageFilters.kt
backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt
backend/data/src/main/kotlin/io/tolgee/service/language/LanguageService.kt
backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationLanguageControllerTest.kt
Added organization-level language endpoints, DTOs, assemblers, repository queries, service methods, and tests.
backend/data/src/main/resources/db/changelog/schema.xml Added glossary-related tables and relationships to the database schema.
backend/data/src/main/kotlin/io/tolgee/model/glossary/Glossary.kt
GlossaryTerm.kt
GlossaryTermTranslation.kt
backend/data/src/main/kotlin/io/tolgee/model/Organization.kt
Project.kt
Introduced glossary, term, translation entities and relationships to organizations/projects.
ee/backend/app/src/main/kotlin/io/tolgee/ee/repository/glossary/GlossaryRepository.kt
GlossaryTermRepository.kt
GlossaryTermTranslationRepository.kt
Added repositories for managing glossaries, terms, and translations with custom queries.
ee/backend/app/src/main/kotlin/io/tolgee/ee/service/glossary/GlossaryService.kt
GlossaryTermService.kt
GlossaryTermTranslationService.kt
Implemented services for glossary, term, and translation business logic, including CRUD, assignment, and highlight features.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/glossary/GlossaryController.kt
GlossaryLanguagesController.kt
GlossaryTermController.kt
GlossaryTermHighlightsController.kt
GlossaryTermTranslationController.kt
Added REST controllers for managing glossaries, terms, translations, highlights, and languages with role-based security and feature checks.
ee/backend/app/src/main/kotlin/io/tolgee/ee/data/glossary/ (multiple files) Added DTOs, request/response models, highlight/position classes, and view interfaces for glossary APIs.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/glossary/ (multiple files) Added HATEOAS model assemblers for glossaries, terms, translations, highlights, positions, and stats.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/model/glossary/ (multiple files) Added HATEOAS resource models for glossary domain objects and highlights.
ee/backend/app/src/main/kotlin/io/tolgee/ee/data/glossary/GlossaryTermWithTranslationsView.kt
GlossaryWithStats.kt
Added view interfaces for glossary term and glossary-with-stats projections.
ee/backend/app/src/main/kotlin/io/tolgee/ee/service/glossary/GlossaryTermService.kt Implements MtGlossaryTermsProvider for machine translation integration.
backend/data/src/main/kotlin/io/tolgee/component/machineTranslation/metadata/Metadata.kt
TranslationGlossaryItem.kt
backend/data/src/main/kotlin/io/tolgee/service/machineTranslation/MetadataProvider.kt
MtGlossaryTermsProvider.kt
MtGlossaryTermsProviderOssImpl.kt
Added glossary term support to machine translation metadata and provider interface.
ee/backend/app/src/main/kotlin/io/tolgee/ee/component/machineTranslation/CloudTolgeeTranslateApiServiceImpl.kt Extended translation requests to include glossary terms.
backend/data/src/main/kotlin/io/tolgee/constants/Feature.kt
Message.kt
Added glossary feature and error messages.
backend/data/src/main/kotlin/io/tolgee/util/stringUtil.kt Added string extension functions for regex matching.
backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/ (multiple files) Added test data builders for glossary entities and test data scenarios.
backend/development/src/main/kotlin/io/tolgee/data/StandardTestDataResult.kt
TestDataGeneratingService.kt
Extended test data models to include glossaries.
ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/glossary/ (multiple files) Added comprehensive integration and permission tests for glossary APIs.
backend/data/src/test/kotlin/io/tolgee/service/machineTranslation/MtBatchTranslatorTest.kt Mocked glossary term provider in MT batch translator tests.
backend/api/src/main/kotlin/io/tolgee/hateoas/language/OrganizationLanguageModel.kt Added new HATEOAS model for organization language.
backend/data/src/main/kotlin/io/tolgee/constants/Feature.kt Added GLOSSARY enum constant.
backend/data/src/main/kotlin/io/tolgee/constants/Message.kt Added glossary-related error messages.
backend/data/src/main/kotlin/io/tolgee/model/Organization.kt
Project.kt
Added glossary relationships to organization and project models.
backend/data/src/main/kotlin/io/tolgee/model/glossary/Glossary.kt
GlossaryTerm.kt
GlossaryTermTranslation.kt
Introduced glossary, term, and translation entities.
ee/backend/app/src/main/kotlin/io/tolgee/ee/repository/glossary/GlossaryRepository.kt
GlossaryTermRepository.kt
GlossaryTermTranslationRepository.kt
Added repositories for glossary domain.
ee/backend/app/src/main/kotlin/io/tolgee/ee/service/glossary/GlossaryService.kt
GlossaryTermService.kt
GlossaryTermTranslationService.kt
Implemented services for glossary management.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/glossary/ (multiple files) Added glossary, term, translation, highlight, and language controllers.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/glossary/ (multiple files) Added HATEOAS model assemblers for glossary domain.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/model/glossary/ (multiple files) Added HATEOAS resource models for glossary domain.
ee/backend/app/src/main/kotlin/io/tolgee/ee/data/glossary/ (multiple files) Added DTOs, request/response models, and view interfaces for glossary.
ee/backend/app/src/main/kotlin/io/tolgee/ee/data/glossary/GlossaryTermWithTranslationsView.kt
GlossaryWithStats.kt
Added view interfaces for glossary projections.
ee/backend/app/src/main/kotlin/io/tolgee/ee/service/glossary/GlossaryTermService.kt Implements MT glossary terms provider.
backend/data/src/main/kotlin/io/tolgee/component/machineTranslation/metadata/Metadata.kt
TranslationGlossaryItem.kt
backend/data/src/main/kotlin/io/tolgee/service/machineTranslation/MetadataProvider.kt
MtGlossaryTermsProvider.kt
MtGlossaryTermsProviderOssImpl.kt
Added glossary term support to machine translation.
ee/backend/app/src/main/kotlin/io/tolgee/ee/component/machineTranslation/CloudTolgeeTranslateApiServiceImpl.kt Extended translation requests to include glossary terms.
backend/data/src/main/kotlin/io/tolgee/constants/Feature.kt
Message.kt
Added glossary feature and error messages.
backend/data/src/main/kotlin/io/tolgee/util/stringUtil.kt Added string regex matching extensions.
backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/ (multiple files) Added test data builders for glossary.
backend/development/src/main/kotlin/io/tolgee/data/StandardTestDataResult.kt
TestDataGeneratingService.kt
Extended test data models to include glossaries.
ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/glossary/ (multiple files) Added integration and permission tests for glossary APIs.
backend/data/src/test/kotlin/io/tolgee/service/machineTranslation/MtBatchTranslatorTest.kt Mocked glossary provider in MT tests.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/internal/DebugFeaturesController.kt
slack/OrganizationSlackController.kt
slack/SlackLoginController.kt
slack/SlackSlashCommandController.kt
SsoAuthController.kt
UserTasksController.kt
TaskController.kt
AiPromptCustomizationController.kt
AdvancedPermissionController.kt
SsoProviderController.kt
ee/service/EeInvitationServiceEeImpl.kt
ee/security/thirdParty/SsoDelegateEe.kt
ee/component/contentDelivery/ContentStorageProviderEeImpl.kt
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/V2UserController.kt
notification/NotificationController.kt
organization/OrganizationProjectController.kt
project/ProjectsController.kt
PreferredOrganizationFacade.kt
ContentDeliveryConfigService.kt
Added or updated suppression annotations for Spring autowiring inspection.
backend/api/src/main/kotlin/io/tolgee/hateoas/ee/webhooks/WebhookConfigModel.kt
WebhookConfigController.kt
Simplified generic type references/imports.
backend/app/src/main/kotlin/io/tolgee/configuration/openApi/OpenApiGroupBuilder.kt
backend/data/src/main/kotlin/io/tolgee/openApiDocs/OpenApiUnstableOperationExtension.kt
Refactored OpenAPI extension logic and added unstable operation annotation.
backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt Broadened parameter type for findAll method.
gradle/e2e.gradle Added CYPRESS_HOST environment variable to E2E test runner.
backend/api/src/test/kotlin/io/tolgee/service/machineTranslation/MtBatchTranslatorTest.kt Mocked glossary term provider in MT batch translator tests.
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/organization/OrganizationLanguageController.kt Added new organization language controller with endpoints for languages and base languages.
backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationLanguageControllerTest.kt Added tests for organization language endpoints.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/glossary/GlossaryController.kt Added main glossary REST controller with CRUD and listing endpoints.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/glossary/GlossaryLanguagesController.kt Added controller for retrieving glossary languages.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/glossary/GlossaryTermController.kt Added controller for glossary term management with CRUD and listing.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/glossary/GlossaryTermHighlightsController.kt Added controller for glossary term highlights retrieval.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/glossary/GlossaryTermTranslationController.kt Added controller for glossary term translations management.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/glossary/ (multiple files) Added HATEOAS assemblers for glossary domain models.
ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/model/glossary/ (multiple files) Added HATEOAS resource models for glossary domain.
ee/backend/app/src/main/kotlin/io/tolgee/ee/data/glossary/ (multiple files) Added DTOs and request/response classes for glossary API.
ee/backend/app/src/main/kotlin/io/tolgee/ee/data/glossary/GlossaryTermWithTranslationsView.kt
GlossaryWithStats.kt
Added view interfaces for glossary projections.
ee/backend/app/src/main/kotlin/io/tolgee/ee/service/glossary/GlossaryService.kt
GlossaryTermService.kt
GlossaryTermTranslationService.kt
Implemented glossary services with business logic and MT integration.
backend/data/src/main/kotlin/io/tolgee/component/machineTranslation/metadata/Metadata.kt
TranslationGlossaryItem.kt
backend/data/src/main/kotlin/io/tolgee/service/machineTranslation/MetadataProvider.kt
MtGlossaryTermsProvider.kt
MtGlossaryTermsProviderOssImpl.kt
Integrated glossary terms into machine translation metadata and providers.
ee/backend/app/src/main/kotlin/io/tolgee/ee/component/machineTranslation/CloudTolgeeTranslateApiServiceImpl.kt Extended translation API service to include glossary terms.
backend/data/src/main/kotlin/io/tolgee/constants/Feature.kt
Message.kt
Added glossary feature flag and error messages.
backend/data/src/main/kotlin/io/tolgee/util/stringUtil.kt Added string regex helper functions.
backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/ (multiple files) Added test data builders and scenarios for glossary entities.
backend/development/src/main/kotlin/io/tolgee/data/StandardTestDataResult.kt
TestDataGeneratingService.kt
Extended standard test data models with glossaries.
ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/glossary/ (multiple files) Added integration and permission tests for glossary APIs.
gradle/e2e.gradle Added environment variable for Cypress host.
e2e/cypress/common/apiCalls/testData/generator.ts
testData.ts
Added glossary test data support and retrieval functions.
e2e/cypress/common/constants.ts Changed default host URL.
e2e/cypress/compounds/glossaries/ (multiple files) Added Cypress page objects for glossary UI components and dialogs.
e2e/cypress/e2e/glossary/ (multiple files) Added Cypress E2E tests for glossary creation, editing, deletion, navigation, highlighting, and permissions.
webapp/src/component/common/TooltipCard.tsx Added styled TooltipCard component.
webapp/src/component/common/form/fields/SearchField.tsx Made onSearch optional and added clear callback ref.
webapp/src/component/common/list/SimpleList.tsx Changed getKey return type to React.Key.
webapp/src/component/languages/CircledLanguageIconList.tsx Renamed component, changed props and data-cy attributes for language icons.
webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx Switched layout to CSS grid, replaced header with HeaderBar component.
webapp/src/component/layout/BaseView.tsx Replaced custom header with HeaderBar, removed header props, updated imports.
webapp/src/component/layout/BaseViewWidth.ts Added width map and utility function for base view widths.
webapp/src/component/layout/HeaderBar.tsx Added new HeaderBar component with flexible header UI.
webapp/src/component/layout/SecondaryBar.tsx Added optional reducedSpacing prop to adjust spacing.
webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx Added infinite multi-select with search and pagination.
webapp/src/component/searchSelect/InfiniteSearchSelect.tsx Added infinite search select with dropdown and loading.
webapp/src/component/searchSelect/InfiniteSearchSelectContent.tsx Changed generic constraints, added itemKey prop, removed getOptionLabel prop.
webapp/src/component/searchSelect/MultiselectItem.tsx Added styled multiselect item with checkbox.
webapp/src/component/searchSelect/SelectItem.tsx Added styled select item component.
webapp/src/constants/GlobalValidationSchema.tsx Added validation schemas for glossary create and glossary term create forms.
webapp/src/constants/links.tsx Added glossary-related route constants and utility URL builder.
webapp/src/custom.d.ts Added utility type KeyOf for React keys.
webapp/src/ee/glossary/components/ (multiple files) Added many React components for glossary UI: messages, selects, panels, lists, dialogs, previews, tags, toolbars, views, and more.
webapp/src/ee/glossary/hooks/ (multiple files) Added React hooks for glossary context, selection, languages, and term highlights.
webapp/src/ee/glossary/views/ (multiple files) Added React views and routers for glossary list, create/edit dialogs, term create/edit dialogs, and glossary view.
webapp/src/eeSetup/EeModuleType.ts Added new type aliases for glossary term models and props.
webapp/src/eeSetup/eeModule.ee.tsx Added glossary panel, routes, and exports for EE module.
webapp/src/eeSetup/eeModule.oss.tsx Added glossary placeholders and exports for OSS module.
webapp/src/index.tsx Wrapped root app in React StrictMode.
webapp/src/service/apiSchema.generated.ts Added comprehensive glossary API schema additions and updates.
webapp/src/service/useSelectionService.ts Added generic selection service hook for managing selections.
webapp/src/translationTools/useFeatures.tsx Added glossary feature key to features hook.
webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx Refactored menu item conditions and added glossaries menu item.
webapp/src/views/projects/DashboardProjectListItem.tsx Replaced ProjectLanguages with CircledLanguageIconList using languages array.
webapp/src/views/projects/ProjectPage.tsx Removed project id prop from ProjectMenu, using hook internally.
webapp/src/views/projects/project/components/BaseLanguageSelect.tsx Added type alias, optional minHeight and disabled props, updated types.
webapp/src/views/projects/projectMenu/ProjectMenu.tsx Removed id prop, used useProject hook internally, updated link params.
webapp/src/views/projects/translations/Screenshots/Screenshots.tsx Changed import path for useScrollStatus hook.
webapp/src/views/projects/translations/ToolsPanel/ToolsPanel.tsx Added appendEditValueString action and passed appendValue prop.
webapp/src/views/projects/translations/ToolsPanel/common/types.ts Added appendValue method to panel content props.
webapp/src/views/projects/translations/ToolsPanel/panelsList.tsx Composed glossaryPanelAdder with translationPanelAdder for panels.
webapp/src/views/projects/translations/TranslationFilters/SubfilterNamespaces.tsx Fixed fetchNextPage call condition, added itemKey prop, removed getOptionLabel.
webapp/src/views/projects/translations/TranslationFilters/SubfilterTags.tsx Added itemKey prop, removed getOptionLabel.
webapp/src/views/projects/translations/TranslationsList/TranslationRead.tsx Added isEditingRow and editingLanguageTag props, passed to TranslationVisual.
webapp/src/views/projects/translations/TranslationsList/TranslationWrite.tsx Added showHighlights prop to TranslationVisual in read-only mode.
webapp/src/views/projects/translations/TranslationsTable/CellLanguage.tsx Narrowed language prop type, removed colIndex, made onResize optional.
webapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsx Added isEditingRow and editingLanguageTag props, passed to TranslationVisual.
webapp/src/views/projects/translations/TranslationsTable/TranslationWrite.tsx Added showHighlights prop to TranslationVisual in read-only mode.
webapp/src/views/projects/translations/TranslationsTable/TranslationsTable.tsx Changed onResize prop to inline function, updated import for useScrollStatus.
webapp/src/views/projects/translations/context/TranslationsContext.ts Added async appendEditValueString action to TranslationsContext.
webapp/src/views/projects/translations/context/services/useEditService.tsx Added appendEditValueString function to useEditService hook.
webapp/src/views/projects/translations/translationVisual/GlossaryHighlight.tsx Added GlossaryHighlight component with tooltip and underline styling.
webapp/src/views/projects/translations/translationVisual/TranslationVisual.tsx Added targetLocale and showHighlights props, passed to TranslationWithPlaceholders.
webapp/src/views/projects/translations/translationVisual/TranslationWithPlaceholders.tsx Added glossary term highlights support, overlap handling, and rendering.
webapp/src/views/projects/translations/useTranslationCell.ts Simplified cursor selection, added editingLanguageTag property.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant API
    participant GlossaryController
    participant GlossaryService
    participant GlossaryRepository
    participant ProjectService

    User->>API: HTTP POST /v2/organizations/{orgId}/glossaries
    API->>GlossaryController: create(organizationId, dto)
    GlossaryController->>GlossaryService: create(organization, dto)
    GlossaryService->>ProjectService: findAll(dto.assignedProjectIds)
    GlossaryService->>GlossaryRepository: save(new Glossary)
    GlossaryService-->>GlossaryController: Glossary
    GlossaryController-->>API: GlossaryModel
    API-->>User: Response (Glossary created)
Loading
sequenceDiagram
    participant User
    participant API
    participant GlossaryTermController
    participant GlossaryTermService
    participant GlossaryTermRepository

    User->>API: HTTP POST /v2/organizations/{orgId}/glossaries/{glossaryId}/terms
    API->>GlossaryTermController: create(organizationId, glossaryId, dto)
    GlossaryTermController->>GlossaryTermService: createWithTranslation(organizationId, glossaryId, dto)
    GlossaryTermService->>GlossaryTermRepository: save(new GlossaryTerm)
    GlossaryTermService-->>GlossaryTermController: (GlossaryTerm, Translation)
    GlossaryTermController-->>API: CreateUpdateGlossaryTermResponse
    API-->>User: Response (Glossary term created)
Loading
sequenceDiagram
    participant User
    participant API
    participant GlossaryTermHighlightsController
    participant GlossaryTermService

    User->>API: POST /v2/projects/{projectId}/glossary-highlights
    API->>GlossaryTermHighlightsController: getHighlights(dto)
    GlossaryTermHighlightsController->>GlossaryTermService: getHighlights(orgId, projectId, text, languageTag)
    GlossaryTermService-->>GlossaryTermHighlightsController: Set<GlossaryTermHighlight>
    GlossaryTermHighlightsController-->>API: CollectionModel<GlossaryTermHighlightModel>
    API-->>User: Response (Highlights)
Loading

Suggested labels

enhancement

Poem

🐇
A glossary garden, neat and new,
With terms and translations for all to view.
Controllers and models, services in line,
Permissions and tests—working just fine!
With highlights and features, this patch is a treat,
Now bunnies and devs can collaborate neat!
🌱📚


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Anty0 Anty0 force-pushed the jirikuchynka/glossaries branch from e4846cf to 81aa318 Compare April 1, 2025 16:04
@Anty0 Anty0 force-pushed the jirikuchynka/glossaries branch 2 times, most recently from 33d4b96 to 19c8f9e Compare April 14, 2025 13:20
@JanCizmar JanCizmar changed the base branch from main to glossaries April 22, 2025 12:40
@Anty0 Anty0 force-pushed the jirikuchynka/glossaries branch from 7eb3a67 to 0487aaa Compare April 29, 2025 13:57
@Anty0 Anty0 changed the base branch from glossaries to main April 29, 2025 14:02
@Anty0 Anty0 changed the base branch from main to glossaries April 29, 2025 14:02
@Anty0 Anty0 force-pushed the jirikuchynka/glossaries branch from 0487aaa to 8ee8c4f Compare April 30, 2025 13:22
@Anty0 Anty0 changed the base branch from glossaries to main April 30, 2025 13:24
@Anty0 Anty0 changed the base branch from main to glossaries April 30, 2025 13:24
@Anty0 Anty0 force-pushed the jirikuchynka/glossaries branch from b58d617 to 872dda5 Compare May 12, 2025 12:10
@Anty0 Anty0 force-pushed the jirikuchynka/glossaries branch from ad7633a to 1eebc2d Compare June 3, 2025 16:41
@Anty0
Copy link
Collaborator Author

Anty0 commented Jun 3, 2025

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Jun 3, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Anty0
Copy link
Collaborator Author

Anty0 commented Jun 4, 2025

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Jun 4, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 42

🔭 Outside diff range comments (1)
webapp/src/service/apiSchema.generated.ts (1)

8153-8179: 🛠️ Refactor suggestion

unknown response bodies hinder type-safety

Several destructive/side‐effect endpoints (delete_11, delete_12, deleteMultiple, etc.) return

This defeats the purpose of generated typings – frontend code must cast manually. Prefer:

  description: No Content

or a small typed payload ({ success: boolean }). Update the OpenAPI spec so the generator emits a meaningful type (e.g. void).

♻️ Duplicate comments (7)
webapp/src/ee/glossary/hooks/GlossaryContext.tsx (1)

14-19: Component naming is misleading.

The component name GlossaryContext suggests a simple context provider, but it's actually a data fetching component. This aligns with past reviewer feedback suggesting this approach might be overkill.

Consider renaming to GlossaryDataProvider or GlossaryLoader to better reflect its purpose, or simplify to a standard context provider as suggested by previous reviewers.

webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (2)

102-123: 🛠️ Refactor suggestion

Extract complex default value calculation logic.

This effect contains complex logic for calculating default values that would benefit from extraction into a well-named helper function, addressing the previous review feedback about method complexity.

+const calculateDefaultLanguageSelection = (
+  glossaryLanguageTags: string[],
+  organizationLanguageTags: string[]
+): string[] => {
+  const uniqueOrganizationLanguageTags = organizationLanguageTags.filter(
+    (l) => !glossaryLanguageTags.includes(l)
+  );
+  return [...glossaryLanguageTags, ...uniqueOrganizationLanguageTags];
+};

   useEffect(() => {
     if (
       value === undefined &&
       glossaryLanguagesLoadable.data &&
       organizationLanguagesLoadable.data
     ) {
-      // Calculate and set default value
       const glossaryLanguageTags = getGlossaryLanguageTags();
       const organizationLanguageTags = getFirstPageOfOrganizationLanguageTags();
-      const uniqueOrganizationLanguageTags = organizationLanguageTags.filter(
-        (l) => !glossaryLanguageTags.includes(l)
-      );
-      onValueChange([
-        ...glossaryLanguageTags,
-        ...uniqueOrganizationLanguageTags,
-      ]);
+      onValueChange(
+        calculateDefaultLanguageSelection(glossaryLanguageTags, organizationLanguageTags)
+      );
     }
   }, [

133-161: 🛠️ Refactor suggestion

Extract language merging logic into helper functions.

The languages useMemo contains complex logic for merging and transforming language data that would benefit from extraction into smaller, well-named functions.

+const transformGlossaryLanguages = (
+  glossaryLanguages: any[]
+): OrganizationLanguageModel[] => {
+  const glossaryLanguagesBaseFirst = toSortedBaseFirst(glossaryLanguages);
+  return glossaryLanguagesBaseFirst.map((l) => {
+    const languageData = languageInfo[l.tag];
+    return {
+      base: l.base,
+      tag: l.tag,
+      flagEmoji: languageData?.flags?.[0] || '',
+      originalName: languageData?.originalName || l.tag,
+      name: languageData?.englishName || l.tag,
+    };
+  });
+};
+
+const transformOrganizationLanguages = (
+  organizationLanguages: OrganizationLanguageModel[],
+  glossaryLanguages: any[]
+): OrganizationLanguageModel[] => {
+  const uniqueOrganizationLanguages = organizationLanguages.filter(
+    (l) => !glossaryLanguages.some((pl) => pl.tag === l.tag)
+  );
+  const organizationLanguagesBaseFirst = toSortedBaseFirst(
+    uniqueOrganizationLanguages
+  );
+  return organizationLanguagesBaseFirst.map((l) => ({ ...l, base: false }));
+};

   const languages: OrganizationLanguageModel[] = useMemo(() => {
-    // List of all glossary and organization languages
-
     const glossaryLanguages =
       glossaryLanguagesLoadable.data?._embedded?.glossaryLanguageDtoList ?? [];
-    const glossaryLanguagesBaseFirst = toSortedBaseFirst(glossaryLanguages);
-    const glossaryLanguagesValue = glossaryLanguagesBaseFirst.map((l) => {
-      const languageData = languageInfo[l.tag];
-      return {
-        base: l.base,
-        tag: l.tag,
-        flagEmoji: languageData?.flags?.[0] || '',
-        originalName: languageData?.originalName || l.tag,
-        name: languageData?.englishName || l.tag,
-      };
-    });
-
-    const uniqueOrganizationLanguages = organizationLanguages.filter(
-      (l) => !glossaryLanguages.some((pl) => pl.tag === l.tag)
-    );
-    const organizationLanguagesBaseFirst = toSortedBaseFirst(
-      uniqueOrganizationLanguages
-    );
-    const organizationLanguagesValue = organizationLanguagesBaseFirst.map(
-      (l) => ({ ...l, base: false })
-    );
-
-    return [...glossaryLanguagesValue, ...organizationLanguagesValue];
+    const glossaryLanguagesValue = transformGlossaryLanguages(glossaryLanguages);
+    const organizationLanguagesValue = transformOrganizationLanguages(
+      organizationLanguages,
+      glossaryLanguages
+    );
+    return [...glossaryLanguagesValue, ...organizationLanguagesValue];
   }, [glossaryLanguagesLoadable.data, organizationLanguages]);
webapp/src/ee/glossary/components/GlossaryBatchToolbar.tsx (1)

29-29: Address the hardcoded margin-left value

The hardcoded margin-left: 5 spacing is still present as discussed in previous reviews. Consider using a more dynamic approach based on the layout context.

e2e/cypress/compounds/glossaries/E2GlossaryView.ts (2)

44-55: 🛠️ Refactor suggestion

Improve selector robustness for translation editing.

Similar to the previous comment, the :contains() selector here could match unintended elements.

-  setTranslation(current: string, translation: string | undefined) {
-    gcy('glossary-translation-cell').filter(`:contains(${current})`).click();
+  setTranslation(current: string, translation: string | undefined) {
+    // Escape special characters for jQuery :contains selector
+    const escapedCurrent = current.replace(/([\\!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1');
+    gcy('glossary-translation-cell').filter(`:contains("${escapedCurrent}")`).click();

71-77: 🛠️ Refactor suggestion

Extract common pattern for selector-based filtering.

The same :contains() pattern is repeated multiple times. Consider extracting it to a helper method.

Add a helper method to encapsulate the filtering logic:

private findTermListItem(termDefaultTranslationOrDescription: string) {
  const escapedText = termDefaultTranslationOrDescription.replace(/([\\!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1');
  return gcy('glossary-term-list-item').filter(`:contains("${escapedText}")`);
}

Then update the methods:

-  toggleTermChecked(termDefaultTranslationOrDescription: string) {
-    gcy('glossary-term-list-item')
-      .filter(`:contains(${termDefaultTranslationOrDescription})`)
-      .find('input[type="checkbox"]')
-      .click();
-  }
+  toggleTermChecked(termDefaultTranslationOrDescription: string) {
+    this.findTermListItem(termDefaultTranslationOrDescription)
+      .find('input[type="checkbox"]')
+      .click();
+  }

-  openEditTermDialog(termDefaultTranslationOrDescription: string) {
-    gcy('glossary-term-list-item')
-      .filter(`:contains(${termDefaultTranslationOrDescription})`)
-      .click();
-    gcy('create-glossary-term-dialog').should('be.visible');
-    return new E2GlossaryTermCreateEditDialog();
-  }
+  openEditTermDialog(termDefaultTranslationOrDescription: string) {
+    this.findTermListItem(termDefaultTranslationOrDescription).click();
+    gcy('create-glossary-term-dialog').should('be.visible');
+    return new E2GlossaryTermCreateEditDialog();
+  }
webapp/src/views/projects/translations/translationVisual/TranslationWithPlaceholders.tsx (1)

29-83: 🛠️ Refactor suggestion

Consider extracting glossary highlight logic into a separate component as previously suggested.

JanCizmar previously suggested separating the glossary placeholder logic into a separate component. The current implementation mixes concerns of placeholder rendering and glossary highlighting, making the component complex and harder to test.

Consider creating a separate component or hook to handle glossary highlight logic:

// useModifiers.ts
export function useModifiers(
  placeholders: Placeholder[],
  highlights: GlossaryTermHighlightModel[]
): Modifier[] {
  return useMemo(() => sortModifiers(placeholders, highlights), [placeholders, highlights]);
}

// Move sortModifiers and related functions to a separate utility file
// glossaryUtils.ts
export function sortModifiers(
  placeholders: Placeholder[],
  highlights: GlossaryTermHighlightModel[]
): Modifier[] {
  // ... existing implementation
}

This would improve testability and separation of concerns.

🧹 Nitpick comments (43)
webapp/src/component/layout/SecondaryBar.tsx (1)

10-10: Consider adding JSDoc documentation for the new prop.

The reducedSpacing prop would benefit from documentation explaining when and why to use it, especially since it's part of a shared layout component.

+  /** When true, removes margin and top padding for tighter layouts */
   reducedSpacing?: boolean;
webapp/src/component/layout/BaseViewWidth.ts (2)

8-8: Improve type safety for string keys.

The current type definition allows any string, not just valid keys from widthMap. Consider constraining it to only valid keys for better type safety.

-export type BaseViewWidth = keyof typeof widthMap | number | undefined;
+export type BaseViewWidth = keyof typeof widthMap | number | undefined;

Actually, the current implementation is already correct! The keyof typeof widthMap properly constrains string values to only valid keys.


10-12: Consider adding input validation or documentation.

The function correctly handles the type conversion logic. However, consider documenting the behavior when an invalid string key is passed (returns undefined) or adding runtime validation if needed.

+/**
+ * Converts a BaseViewWidth to a numeric width value.
+ * @param width - Either a predefined width key, numeric value, or undefined
+ * @returns The corresponding numeric width or undefined for 'max' and invalid keys
+ */
 export function getBaseViewWidth(width: BaseViewWidth) {
   return typeof width === 'string' ? widthMap[width] : width;
 }
webapp/src/component/common/form/fields/SearchField.tsx (1)

28-33: Consider moving the ref assignment into a useEffect for better performance.

The current implementation assigns the clear callback on every render. Consider wrapping this in a useEffect to avoid unnecessary work:

-  if (clearCallbackRef !== undefined) {
-    clearCallbackRef.current = () => {
-      setSearch('');
-      onSearch?.('');
-    };
-  }
+  useEffect(() => {
+    if (clearCallbackRef !== undefined) {
+      clearCallbackRef.current = () => {
+        setSearch('');
+        onSearch?.('');
+      };
+    }
+  }, [clearCallbackRef, onSearch]);
webapp/src/ee/glossary/hooks/useSelectedGlossaryLanguages.ts (1)

4-21: Consider adding early return for better robustness.

While the null checking fix above addresses the immediate issue, consider adding an early return when glossary is not available for better error handling.

export const useSelectedGlossaryLanguages = () => {
  const glossary = useGlossary();

+  if (!glossary) {
+    return [undefined, () => {}] as const;
+  }

  const [selected, setSelected] = useState<string[] | undefined>(undefined);
  // ... rest of the hook
webapp/src/ee/glossary/components/GlossaryTermCreateEditFields.tsx (1)

1-1: Consider using FC instead of VFC.

VFC (VoidFunctionComponent) is deprecated in favor of FC (FunctionComponent) in newer React versions.

-import { VFC } from 'react';
+import { FC } from 'react';
-export const GlossaryTermCreateEditFields: VFC = () => {
+export const GlossaryTermCreateEditFields: FC = () => {
webapp/src/ee/glossary/views/GlossaryTermCreateDialog.tsx (1)

37-62: Consider adding error handling for the mutation.

The mutation currently only handles success cases. Consider adding error handling to provide user feedback when the operation fails.

  const save = async (values: CreateOrUpdateGlossaryTermRequest) => {
    mutation.mutate(
      {
        path: {
          organizationId: preferredOrganization!.id,
          glossaryId: glossary.id,
        },
        content: {
          'application/json': values,
        },
      },
      {
        onSuccess() {
          messageService.success(
            <T keyName="glossary_term_create_success_message" />
          );
          onFinished();
        },
+       onError(error) {
+         messageService.error(
+           <T keyName="glossary_term_create_error_message" />
+         );
+       },
      }
    );
  };
webapp/src/ee/glossary/hooks/useGlossaryTermHighlights.ts (1)

38-42: Simplify conditional logic.

The same conditions are checked both in the API query's enabled option and in this return statement. Consider consolidating the logic.

- if (!glossaryFeature || !hasText || !enabled || !highlights.data) {
+ if (!highlights.data) {
    return [];
  }

  return highlights.data._embedded?.glossaryHighlights ?? [];

The feature flag and text validation are already handled by the enabled option in the query, making this check redundant.

webapp/src/ee/glossary/components/GlossariesPanel.tsx (1)

62-83: Consider performance optimization for duplicate filtering.

The current approach uses array filtering with includes() which has O(n²) complexity. For better performance with larger datasets, consider using a Set.

-  const found: number[] = [];
+  const found = new Set<number>();
   const previews = terms
     .map((v) => v.value)
     .filter((term) => {
-      if (found.includes(term.id)) {
+      if (found.has(term.id)) {
         return false;
       }
-      found.push(term.id);
+      found.add(term.id);
       return true;
     })
webapp/src/ee/glossary/components/GlossaryListItem.tsx (1)

82-91: Overly complex language array creation.

Creating a full language object structure for displaying a single language seems unnecessarily complex. This could be simplified since you're only showing the base language.

Consider simplifying this to just pass the necessary data directly to CircledLanguageIconList or create a simpler structure:

- const languages = [
-   {
-     base: true,
-     flagEmoji: languageData?.flags?.[0] || '',
-     id: 0,
-     name: languageData?.englishName || languageTag,
-     originalName: languageData?.originalName || languageTag,
-     tag: languageTag,
-   },
- ];
+ const language = {
+   flagEmoji: languageData?.flags?.[0] || '',
+   name: languageData?.englishName || languageTag,
+   tag: languageTag,
+ };
webapp/src/ee/glossary/components/GlossaryEmptyListMessage.tsx (2)

82-88: Remove hidden elements from DOM.

Using visibility: 'hidden' keeps the element in the DOM and affects layout, which is not ideal for accessibility and performance.

Consider conditional rendering instead:

- <Link
-   href="https://docs.tolgee.io/platform/projects_and_organizations/glossary"
-   sx={{ visibility: 'hidden' }}
- >
-   <Typography variant="body2">
-     <T keyName="glossary_empty_placeholder_add_term_best_practices" />
-   </Typography>
- </Link>
+ {/* TODO: Uncomment when best practices content is ready */}
+ {false && (
+   <Link href="https://docs.tolgee.io/platform/projects_and_organizations/glossary">
+     <Typography variant="body2">
+       <T keyName="glossary_empty_placeholder_add_term_best_practices" />
+     </Typography>
+   </Link>
+ )}

90-112: Hidden import card suggests incomplete feature.

The entire import card is hidden with display: 'none', suggesting this feature is not ready for release.

Consider removing this card entirely until the import feature is implemented, or make it conditional based on a feature flag:

- <StyledCard elevation={0} sx={{ display: 'none' }}>
+ {/* TODO: Implement import functionality */}
+ {false && (
+   <StyledCard elevation={0}>
     <StyledUploadCloud02 />
     ...
-   </StyledCard>
+   </StyledCard>
+ )}
webapp/src/ee/glossary/components/GlossaryTermCreateEditForm.tsx (3)

16-18: Improve type intersection pattern.

The type intersection creates a union of both request types, which may include conflicting properties. Consider using a more explicit approach or ensure the schemas are designed to be safely intersected.

-export type CreateOrUpdateGlossaryTermRequest =
-  CreateGlossaryTermWithTranslationRequest &
-    UpdateGlossaryTermWithTranslationRequest;
+export type CreateOrUpdateGlossaryTermRequest = 
+  | CreateGlossaryTermWithTranslationRequest 
+  | UpdateGlossaryTermWithTranslationRequest;

25-25: Consider more responsive width calculation.

The fixed width calculation min(calc(100vw - 64px), 600px) uses magic numbers and may not work well across all viewport sizes and orientations.

-  width: min(calc(100vw - 64px), 600px);
+  width: min(calc(100vw - ${({ theme }) => theme.spacing(8)}), 600px);
+  max-width: 100%;

59-65: Enhance loading state clarity.

The undefined check for initialValues could be more explicit about the loading intent and consider handling potential error states.

-  if (initialValues === undefined) {
+  if (!initialValues) {
     return (
       <StyledLoading>
         <SpinnerProgress />
       </StyledLoading>
     );
   }
webapp/src/ee/glossary/hooks/useGlossaryTerms.ts (1)

26-28: Consider making pagination configuration configurable.

Hard-coded values for page size and sort order reduce flexibility and reusability of the hook.

+type Props = {
+  search: string | undefined;
+  languageTags: string[] | undefined;
+  pageSize?: number;
+  sortOrder?: string[];
+};

-export const useGlossaryTerms = ({ search, languageTags }: Props) => {
+export const useGlossaryTerms = ({ 
+  search, 
+  languageTags, 
+  pageSize = 30,
+  sortOrder = ['id,desc']
+}: Props) => {
   // ...
   const query = {
     search,
     languageTags,
-    size: 30,
-    sort: ['id,desc'],
+    size: pageSize,
+    sort: sortOrder,
   };
webapp/src/component/searchSelect/InfiniteSearchSelect.tsx (2)

93-94: Use optional chaining for cleaner code.

The static analysis tool correctly identified that this can be simplified using optional chaining.

-    onSearchChange && onSearchChange('');
+    onSearchChange?.('');
🧰 Tools
🪛 Biome (1.9.4)

[error] 93-93: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


145-145: Consider safer access to anchorEl.current.

The non-null assertion could throw if anchorEl.current is unexpectedly null. While this is likely safe given the context, consider defensive programming.

-          anchorEl={anchorEl.current!}
+          anchorEl={anchorEl.current ?? undefined}
webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (1)

44-51: Add error handling for API queries.

Consider adding error handling for the API queries to provide better user experience when data fetching fails.

if (glossaryLanguagesLoadable.error || organizationLanguagesLoadable.error) {
  // Handle error state - show error message or fallback UI
}

Also applies to: 62-88

webapp/src/ee/glossary/components/ScrollArrows.tsx (3)

8-8: Consider making the arrow size configurable.

The hardcoded ARROW_SIZE constant might not work well across different screen sizes and use cases. Consider making this configurable via props.


81-89: Make scroll distance responsive and configurable.

The hardcoded 350px scroll distance isn't responsive and may not work well on different screen sizes or content layouts.

Consider making the scroll distance dynamic:

const handleScroll = (direction: 'left' | 'right') => {
  const element = verticalScrollRef.current;
  if (element) {
    const position = element.scrollLeft;
+   const scrollDistance = Math.min(350, element.clientWidth * 0.8);
    element.scrollTo({
-     left: position + (direction === 'left' ? -350 : +350),
+     left: position + (direction === 'left' ? -scrollDistance : +scrollDistance),
    });
  }
};

91-93: Document the minimal height requirement.

The hasMinimalHeight check silently hides the component below 400px height. Consider documenting this behavior or making it configurable.

Add a comment explaining the rationale:

+ // Hide scroll arrows on very small screens where they would interfere with content
  if (!hasMinimalHeight) {
    return null;
  }
e2e/cypress/e2e/glossary/navigation.cy.ts (1)

35-44: Consider testing Member access with Member organization data.

Both tests use the Owner organization data. For proper Member role testing, consider using organization data where the user is a Member.

const testItself = () => {
- const slug = getOrganizationByNameFromTestData(data, 'Owner').slug;
+ const orgName = cy.state('loginRole') === 'Member' ? 'Member' : 'Owner';
+ const slug = getOrganizationByNameFromTestData(data, orgName).slug;
  cy.visit(`${HOST}/organizations/${slug}/profile`);
  gcy('settings-menu-item').filter(':contains("Glossaries")').click();

Or create separate test functions for each role if the access patterns differ significantly.

webapp/src/ee/glossary/components/GlossaryBaseLanguageSelect.tsx (2)

38-39: Document the error handling workaround.

The comment indicates a schema issue but the workaround handles it properly. Consider adding more context about when this occurs.

- // Formik returns error as object - schema is incorrect...
+ // Formik returns error as nested object when using Yup schema validation
+ // Extract the specific field error from the error object
  const error = (meta.error as any)?.tag;

120-139: Consider adding loading state indication.

The component doesn't show any loading state while fetching data, which could lead to a poor user experience during slow network conditions.

Consider passing the loading state to the InfiniteSearchSelect:

<InfiniteSearchSelect
  items={data}
  selected={value}
  queryResult={dataLoadable}
+ loading={dataLoadable.isLoading}
  itemKey={(item) => item.tag}
  search={search}
  onClearSelected={() => setValue(undefined)}
  onSearchChange={setSearch}
  onFetchMore={handleFetchMore}
  renderItem={renderItem}
  labelItem={labelItem}
  label={t('create_glossary_field_base_language')}
  error={meta.touched && error}
  searchPlaceholder={t('language_search_placeholder')}
  disabled={disabled}
/>
webapp/src/views/projects/project/components/BaseLanguageSelect.tsx (1)

24-24: Consider simplifying the default value assignment.

The logical OR operation might be unnecessary if minHeight is explicitly passed as false. Consider using nullish coalescing or a more explicit default value pattern.

-  const minHeight = props.minHeight || false;
+  const minHeight = props.minHeight ?? false;
webapp/src/ee/glossary/components/GlossaryViewListRow.tsx (2)

45-47: Consider extracting permission logic to a custom hook.

The permission check logic could be extracted into a reusable hook like useCanEditGlossary() for better maintainability and testing.

// In a separate hooks file
export const useCanEditGlossary = () => {
  const { preferredOrganization } = usePreferredOrganization();
  return ['OWNER', 'MAINTAINER'].includes(
    preferredOrganization?.currentUserRole || ''
  );
};

88-106: Consider extracting magic numbers to named constants.

The height calculation function uses magic numbers that could be extracted to named constants for better maintainability.

+const HEIGHT_CONSTANTS = {
+  BASE: 58,
+  DEFAULT_FALLBACK: 84,
+  TAGS: 25,
+  DESCRIPTION: 26,
+} as const;

export const estimateGlossaryViewListRowHeight = (
  row?: SimpleGlossaryTermWithTranslationsModel
): number => {
  if (!row) {
-    return 84;
+    return HEIGHT_CONSTANTS.DEFAULT_FALLBACK;
  }

-  const base = 58;
+  const base = HEIGHT_CONSTANTS.BASE;
  const tags =
    row.flagNonTranslatable ||
    row.flagAbbreviation ||
    row.flagCaseSensitive ||
    row.flagForbiddenTerm
-      ? 25
+      ? HEIGHT_CONSTANTS.TAGS
      : 0;
-  const description = row.description ? 26 : 0;
+  const description = row.description ? HEIGHT_CONSTANTS.DESCRIPTION : 0;

  return base + tags + description;
};
webapp/src/component/layout/HeaderBar.tsx (1)

37-37: Replace deprecated React.VFC with React.FC

React.VFC has been deprecated. Use React.FC instead for better future compatibility.

-export const HeaderBar: React.VFC<HeaderBarProps> = (props) => {
+export const HeaderBar: React.FC<HeaderBarProps> = (props) => {
webapp/src/ee/glossary/components/GlossaryListTranslationCell.tsx (1)

66-66: Replace deprecated React.VFC with React.FC

React.VFC has been deprecated. Use React.FC instead.

-export const GlossaryListTranslationCell: React.VFC<Props> = ({
+export const GlossaryListTranslationCell: React.FC<Props> = ({
webapp/src/ee/glossary/components/GlossaryBatchToolbar.tsx (2)

48-48: Replace deprecated React.VFC with React.FC

React.VFC has been deprecated. Use React.FC instead.

-export const GlossaryBatchToolbar: React.VFC<Props> = ({
+export const GlossaryBatchToolbar: React.FC<Props> = ({

116-118: Consider making the Select component functional

The Select component appears to be decorative only with a single "Delete terms" option. Consider either making it functional with multiple batch operations or simplifying the UI if only one action is available.

If only delete operation is needed:

-      <Select variant="outlined" size="small" value={0} sx={{ minWidth: 250 }}>
-        <MenuItem value={0}>Delete terms</MenuItem>
-      </Select>
+      <Typography variant="body2">Delete selected terms</Typography>
e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1)

79-79: Remove trailing empty line.

-}
-
+}
webapp/src/views/projects/translations/translationVisual/TranslationWithPlaceholders.tsx (1)

49-60: Consider optimizing the overlap detection algorithm.

The current implementation has O(n*m) complexity where n is the number of existing modifiers and m is the number of highlights. For large texts with many highlights, this could become a performance bottleneck.

Consider using an interval tree or sorted data structure to improve performance for overlap detection if this becomes a bottleneck with large texts.

webapp/src/ee/glossary/components/GlossaryViewListHeader.tsx (2)

45-48: Extract grid template calculation to improve readability.

The inline grid template calculation makes the component harder to read. Consider extracting it to a helper function.

+const calculateGridTemplate = (languageCount: number) => {
+  const additionalColumns = Math.max(0, languageCount - 1);
+  return 'minmax(300px, 1fr)' + ' minmax(200px, 1fr)'.repeat(additionalColumns);
+};

 export const GlossaryViewListHeader: React.FC<Props> = ({
   selectedLanguages,
   selectionService,
 }) => {
   return (
     <StyledHeaderRow
       style={{
-        gridTemplateColumns:
-          'minmax(300px, 1fr)' +
-          ' minmax(200px, 1fr)'.repeat((selectedLanguages?.length || 1) - 1),
+        gridTemplateColumns: calculateGridTemplate(selectedLanguages?.length || 1),
       }}
     >

62-62: Add a comment explaining why the first language is skipped.

The code slices from index 1, suggesting the first language has special treatment, but this isn't documented.

       </StyledHeaderCell>
+      {/* Skip the first language as it's displayed in the first column with terms */}
       {selectedLanguages?.slice(1)?.map((tag, i) => {
webapp/src/constants/links.tsx (2)

301-312: Alias creates dead-weight – it’s never different from ORGANIZATION_GLOSSARY

ORGANIZATION_GLOSSARY_VIEW is just a reference to ORGANIZATION_GLOSSARY and does not add any semantic difference or extra behaviour.
Unless you anticipate diverging paths in the near future, the alias only bloats the public surface and forces future refactors to keep two names in sync.

-  static ORGANIZATION_GLOSSARY_VIEW = LINKS.ORGANIZATION_GLOSSARY;

438-448: Prefer URLSearchParams for query construction

Manually concatenating ?search=${encodedSearch} works, but using URLSearchParams is safer (handles additional parameters, encodings, & joining, etc.) and self-documenting.

-export const getGlossaryTermSearchUrl = (
-  organizationSlug: string,
-  glossaryId: number,
-  search: string
-) => {
-  const encodedSearch = encodeURIComponent(search.toString());
-  return `${LINKS.ORGANIZATION_GLOSSARY.build({
-    [PARAMS.ORGANIZATION_SLUG]: organizationSlug,
-    [PARAMS.GLOSSARY_ID]: glossaryId,
-  })}?search=${encodedSearch}`;
-};
+export const getGlossaryTermSearchUrl = (
+  organizationSlug: string,
+  glossaryId: number,
+  search: string
+) => {
+  const params = new URLSearchParams({ search });
+  return `${LINKS.ORGANIZATION_GLOSSARY.build({
+    [PARAMS.ORGANIZATION_SLUG]: organizationSlug,
+    [PARAMS.GLOSSARY_ID]: glossaryId,
+  })}?${params.toString()}`;
+};
webapp/src/ee/glossary/components/GlossaryTermsList.tsx (1)

160-166: Dependency array won’t react to language content changes

deps={[selectedLanguages]} passes the array reference to ScrollArrows.
If the caller mutates the array in-place (push/pop), the reference stays the same and the effect inside ScrollArrows won’t run.

Unless you always create a fresh array, pass a stable key instead:

-        deps={[selectedLanguages]}
+        deps={[selectedLanguages?.join(',')]}
webapp/src/component/layout/BaseView.tsx (1)

94-95: ...props leaks non-header values into HeaderBar

BaseViewProps spreads the full prop bag to HeaderBar, including layout-only fields (allCentered, navigation, etc.).
Although TypeScript’s structural typing allows the call, the extra fields are unused and can trigger needless re-renders when they change.

Create a dedicated object with only HeaderBarProps to avoid prop-bloat:

-        <HeaderBar noBorder={Boolean(displayNavigation)} {...props} />
+        <HeaderBar
+          noBorder={Boolean(displayNavigation)}
+          {...((props as unknown) as HeaderBarProps)}
+        />

(or explicitly pick the relevant fields).

webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx (2)

18-21: Consider using a more specific type instead of any.

The _embedded property uses any type, which reduces type safety. Consider defining a more specific interface or using a generic type parameter.

-type PagedResult = {
-  _embedded?: any;
-  page?: components['schemas']['PageMetadata'];
-};
+type PagedResult<T = unknown> = {
+  _embedded?: T;
+  page?: components['schemas']['PageMetadata'];
+};

92-92: Use optional chaining for better null safety.

Apply the static analysis suggestion to use optional chaining instead of logical AND operator.

-onSearchChange && onSearchChange('');
+onSearchChange?.('');
🧰 Tools
🪛 Biome (1.9.4)

[error] 92-92: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

webapp/src/service/apiSchema.generated.ts (1)

82-104: Avoid hand-editing generated files

apiSchema.generated.ts appears to be produced by an OpenAPI generator. Committing hand changes will be overwritten on the next generation run and will pollute diffs.
Consider:

  1. Add the file to .gitignore, or
  2. Commit it only from CI after generation, or
  3. Keep it, but document the exact generation command so reviewers can diff the real source (the yaml/json spec) instead of the artefact.

Leaving it as-is makes reviews noisy and increases merge-conflict risk.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad7633a and e2c0ab7.

⛔ Files ignored due to path filters (1)
  • webapp/src/svgs/icons/glossary-empty.svg is excluded by !**/*.svg
📒 Files selected for processing (108)
  • e2e/cypress/common/apiCalls/testData/generator.ts (1 hunks)
  • e2e/cypress/common/apiCalls/testData/testData.ts (2 hunks)
  • e2e/cypress/common/constants.ts (1 hunks)
  • e2e/cypress/compounds/glossaries/E2GlossariesView.ts (1 hunks)
  • e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1 hunks)
  • e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1 hunks)
  • e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1 hunks)
  • e2e/cypress/e2e/glossary/create.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/createTerm.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/delete.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/deleteTerm.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/edit.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/editTerm.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/editTranslation.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/highlighting.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/navigation.cy.ts (1 hunks)
  • e2e/cypress/e2e/glossary/panel.cy.ts (1 hunks)
  • e2e/cypress/e2e/projects/projectsListDashboard.cy.ts (1 hunks)
  • e2e/cypress/support/dataCyType.d.ts (4 hunks)
  • e2e/cypress/support/e2e.ts (1 hunks)
  • webapp/src/component/common/TooltipCard.tsx (1 hunks)
  • webapp/src/component/common/form/fields/SearchField.tsx (1 hunks)
  • webapp/src/component/common/list/SimpleList.tsx (1 hunks)
  • webapp/src/component/languages/CircledLanguageIconList.tsx (4 hunks)
  • webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx (2 hunks)
  • webapp/src/component/layout/BaseView.tsx (3 hunks)
  • webapp/src/component/layout/BaseViewWidth.ts (1 hunks)
  • webapp/src/component/layout/HeaderBar.tsx (1 hunks)
  • webapp/src/component/layout/SecondaryBar.tsx (1 hunks)
  • webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx (1 hunks)
  • webapp/src/component/searchSelect/InfiniteSearchSelect.tsx (1 hunks)
  • webapp/src/component/searchSelect/InfiniteSearchSelectContent.tsx (4 hunks)
  • webapp/src/component/searchSelect/MultiselectItem.tsx (1 hunks)
  • webapp/src/component/searchSelect/SelectItem.tsx (1 hunks)
  • webapp/src/constants/GlobalValidationSchema.tsx (1 hunks)
  • webapp/src/constants/links.tsx (4 hunks)
  • webapp/src/custom.d.ts (1 hunks)
  • webapp/src/ee/glossary/components/AddFirstGlossaryMessage.tsx (1 hunks)
  • webapp/src/ee/glossary/components/AssignedProjectsSelect.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossariesEmptyListMessage.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossariesPanel.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryBaseLanguageSelect.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryBatchToolbar.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryCreateEditFields.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryCreateEditForm.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryEmptyListMessage.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryListItem.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryListItemMenu.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryListStyledRowCell.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryListTermCell.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryListTranslationCell.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryTermCreateEditFields.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryTermCreateEditForm.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryTermPreview.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryTermTags.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryTermsList.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryViewBody.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryViewListHeader.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryViewListRow.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryViewToolbar.tsx (1 hunks)
  • webapp/src/ee/glossary/components/GlossaryViewTopbar.tsx (1 hunks)
  • webapp/src/ee/glossary/components/ProjectSelect.tsx (1 hunks)
  • webapp/src/ee/glossary/components/ScrollArrows.tsx (1 hunks)
  • webapp/src/ee/glossary/hooks/GlossaryContext.tsx (1 hunks)
  • webapp/src/ee/glossary/hooks/GlossaryProvider.tsx (1 hunks)
  • webapp/src/ee/glossary/hooks/useGlossary.ts (1 hunks)
  • webapp/src/ee/glossary/hooks/useGlossaryContext.ts (1 hunks)
  • webapp/src/ee/glossary/hooks/useGlossaryTermHighlights.ts (1 hunks)
  • webapp/src/ee/glossary/hooks/useGlossaryTerms.ts (1 hunks)
  • webapp/src/ee/glossary/hooks/useSelectedGlossaryLanguages.ts (1 hunks)
  • webapp/src/ee/glossary/views/GlossariesListView.tsx (1 hunks)
  • webapp/src/ee/glossary/views/GlossaryCreateDialog.tsx (1 hunks)
  • webapp/src/ee/glossary/views/GlossaryEditDialog.tsx (1 hunks)
  • webapp/src/ee/glossary/views/GlossaryRouter.tsx (1 hunks)
  • webapp/src/ee/glossary/views/GlossaryTermCreateDialog.tsx (1 hunks)
  • webapp/src/ee/glossary/views/GlossaryTermEditDialog.tsx (1 hunks)
  • webapp/src/ee/glossary/views/GlossaryView.tsx (1 hunks)
  • webapp/src/eeSetup/EeModuleType.ts (1 hunks)
  • webapp/src/eeSetup/eeModule.ee.tsx (5 hunks)
  • webapp/src/eeSetup/eeModule.oss.tsx (3 hunks)
  • webapp/src/index.tsx (2 hunks)
  • webapp/src/service/apiSchema.generated.ts (42 hunks)
  • webapp/src/service/useSelectionService.ts (1 hunks)
  • webapp/src/translationTools/useFeatures.tsx (1 hunks)
  • webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx (3 hunks)
  • webapp/src/views/projects/DashboardProjectListItem.tsx (2 hunks)
  • webapp/src/views/projects/ProjectPage.tsx (1 hunks)
  • webapp/src/views/projects/project/components/BaseLanguageSelect.tsx (3 hunks)
  • webapp/src/views/projects/projectMenu/ProjectMenu.tsx (3 hunks)
  • webapp/src/views/projects/translations/Screenshots/Screenshots.tsx (1 hunks)
  • webapp/src/views/projects/translations/ToolsPanel/ToolsPanel.tsx (2 hunks)
  • webapp/src/views/projects/translations/ToolsPanel/common/types.ts (1 hunks)
  • webapp/src/views/projects/translations/ToolsPanel/panelsList.tsx (2 hunks)
  • webapp/src/views/projects/translations/TranslationFilters/SubfilterNamespaces.tsx (2 hunks)
  • webapp/src/views/projects/translations/TranslationFilters/SubfilterTags.tsx (1 hunks)
  • webapp/src/views/projects/translations/TranslationsList/TranslationRead.tsx (2 hunks)
  • webapp/src/views/projects/translations/TranslationsList/TranslationWrite.tsx (1 hunks)
  • webapp/src/views/projects/translations/TranslationsTable/CellLanguage.tsx (3 hunks)
  • webapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsx (2 hunks)
  • webapp/src/views/projects/translations/TranslationsTable/TranslationWrite.tsx (1 hunks)
  • webapp/src/views/projects/translations/TranslationsTable/TranslationsTable.tsx (3 hunks)
  • webapp/src/views/projects/translations/context/TranslationsContext.ts (1 hunks)
  • webapp/src/views/projects/translations/context/services/useEditService.tsx (1 hunks)
  • webapp/src/views/projects/translations/translationVisual/GlossaryHighlight.tsx (1 hunks)
  • webapp/src/views/projects/translations/translationVisual/TranslationVisual.tsx (2 hunks)
  • webapp/src/views/projects/translations/translationVisual/TranslationWithPlaceholders.tsx (4 hunks)
  • webapp/src/views/projects/translations/useTranslationCell.ts (2 hunks)
✅ Files skipped from review due to trivial changes (15)
  • webapp/src/views/projects/translations/Screenshots/Screenshots.tsx
  • webapp/src/views/projects/translations/TranslationsList/TranslationWrite.tsx
  • e2e/cypress/common/constants.ts
  • webapp/src/index.tsx
  • e2e/cypress/support/e2e.ts
  • webapp/src/ee/glossary/hooks/useGlossary.ts
  • webapp/src/ee/glossary/hooks/useGlossaryContext.ts
  • webapp/src/component/common/list/SimpleList.tsx
  • webapp/src/translationTools/useFeatures.tsx
  • webapp/src/component/common/TooltipCard.tsx
  • webapp/src/ee/glossary/components/GlossariesEmptyListMessage.tsx
  • webapp/src/ee/glossary/components/GlossaryListStyledRowCell.tsx
  • webapp/src/ee/glossary/hooks/GlossaryProvider.tsx
  • webapp/src/ee/glossary/components/GlossaryViewToolbar.tsx
  • webapp/src/eeSetup/EeModuleType.ts
🧰 Additional context used
🧬 Code Graph Analysis (32)
webapp/src/views/projects/translations/ToolsPanel/ToolsPanel.tsx (1)
webapp/src/views/projects/translations/context/TranslationsContext.ts (1)
  • appendEditValueString (212-215)
webapp/src/views/projects/translations/ToolsPanel/panelsList.tsx (2)
webapp/src/eeSetup/eeModule.ee.tsx (2)
  • glossaryPanelAdder (271-283)
  • translationPanelAdder (254-269)
webapp/src/eeSetup/eeModule.oss.tsx (2)
  • glossaryPanelAdder (54-54)
  • translationPanelAdder (53-53)
webapp/src/ee/glossary/views/GlossaryRouter.tsx (3)
webapp/src/ee/glossary/hooks/GlossaryContext.tsx (1)
  • GlossaryContext (14-79)
webapp/src/constants/links.tsx (1)
  • LINKS (68-421)
webapp/src/ee/glossary/views/GlossaryView.tsx (1)
  • GlossaryView (11-66)
webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx (1)
webapp/src/constants/links.tsx (1)
  • LINKS (68-421)
webapp/src/ee/glossary/hooks/useSelectedGlossaryLanguages.ts (1)
webapp/src/ee/glossary/hooks/useGlossary.ts (1)
  • useGlossary (3-3)
webapp/src/views/projects/projectMenu/ProjectMenu.tsx (1)
webapp/src/constants/links.tsx (1)
  • LINKS (68-421)
e2e/cypress/e2e/glossary/editTerm.cy.ts (4)
e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1)
  • E2GlossaryView (10-78)
e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1)
  • E2GlossaryTermCreateEditDialog (3-63)
e2e/cypress/common/apiCalls/testData/testData.ts (1)
  • glossaryTestData (124-124)
e2e/cypress/common/shared.ts (1)
  • gcy (28-29)
webapp/src/component/searchSelect/SelectItem.tsx (2)
webapp/src/component/ListComponents.tsx (1)
  • CompactMenuItem (17-20)
webapp/src/component/searchSelect/MultiselectItem.tsx (1)
  • MultiselectItem (36-56)
e2e/cypress/e2e/glossary/editTranslation.cy.ts (4)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
  • TestDataStandardResponse (24-34)
e2e/cypress/common/apiCalls/testData/testData.ts (1)
  • glossaryTestData (124-124)
e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1)
  • E2GlossaryView (10-78)
e2e/cypress/common/shared.ts (1)
  • gcy (28-29)
webapp/src/views/projects/translations/TranslationsTable/TranslationsTable.tsx (1)
webapp/src/views/projects/translations/useColumns.ts (1)
  • startResize (45-47)
e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1)
e2e/cypress/common/shared.ts (1)
  • gcy (28-29)
e2e/cypress/e2e/glossary/createTerm.cy.ts (4)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
  • TestDataStandardResponse (24-34)
e2e/cypress/common/apiCalls/testData/testData.ts (1)
  • glossaryTestData (124-124)
e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1)
  • E2GlossaryView (10-78)
e2e/cypress/common/shared.ts (1)
  • gcy (28-29)
webapp/src/component/searchSelect/MultiselectItem.tsx (1)
webapp/src/component/ListComponents.tsx (1)
  • CompactMenuItem (17-20)
webapp/src/ee/glossary/components/GlossaryEmptyListMessage.tsx (2)
webapp/src/component/common/EmptyState.tsx (1)
  • EmptyState (24-42)
webapp/src/constants/links.tsx (1)
  • Link (1-45)
e2e/cypress/e2e/glossary/highlighting.cy.ts (2)
e2e/cypress/common/apiCalls/testData/testData.ts (2)
  • glossaryTestData (124-124)
  • getProjectByNameFromTestData (193-198)
e2e/cypress/common/shared.ts (1)
  • gcy (28-29)
e2e/cypress/e2e/glossary/navigation.cy.ts (5)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
  • TestDataStandardResponse (24-34)
e2e/cypress/common/apiCalls/testData/testData.ts (2)
  • glossaryTestData (124-124)
  • getOrganizationByNameFromTestData (170-175)
e2e/cypress/common/constants.ts (1)
  • HOST (1-1)
e2e/cypress/common/shared.ts (1)
  • gcy (28-29)
e2e/cypress/compounds/glossaries/E2GlossariesView.ts (1)
  • E2GlossariesView (8-53)
webapp/src/views/projects/translations/TranslationsTable/CellLanguage.tsx (1)
webapp/src/service/apiSchema.generated.ts (1)
  • components (969-5405)
webapp/src/ee/glossary/views/GlossaryTermCreateDialog.tsx (4)
webapp/src/ee/glossary/components/GlossaryTermCreateEditForm.tsx (2)
  • CreateOrUpdateGlossaryTermRequest (16-18)
  • GlossaryTermCreateEditForm (50-102)
webapp/src/globalContext/helpers.tsx (1)
  • usePreferredOrganization (31-43)
webapp/src/ee/glossary/hooks/useGlossary.ts (1)
  • useGlossary (3-3)
webapp/src/service/http/useQueryApi.ts (1)
  • useApiMutation (224-265)
webapp/src/ee/glossary/hooks/useGlossaryTermHighlights.ts (5)
webapp/src/eeSetup/EeModuleType.ts (2)
  • GlossaryTermHighlightModel (40-41)
  • GlossaryTermHighlightsProps (45-49)
webapp/src/eeSetup/eeModule.ee.tsx (1)
  • useGlossaryTermHighlights (414-416)
webapp/src/eeSetup/eeModule.oss.tsx (1)
  • useGlossaryTermHighlights (65-67)
webapp/src/globalContext/helpers.tsx (1)
  • useEnabledFeatures (49-61)
webapp/src/service/http/useQueryApi.ts (1)
  • useApiQuery (119-141)
e2e/cypress/compounds/glossaries/E2GlossariesView.ts (5)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
  • TestDataStandardResponse (24-34)
e2e/cypress/common/apiCalls/testData/testData.ts (1)
  • getOrganizationByNameFromTestData (170-175)
e2e/cypress/common/constants.ts (1)
  • HOST (1-1)
e2e/cypress/common/shared.ts (2)
  • gcy (28-29)
  • confirmHardMode (63-72)
e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1)
  • E2GlossaryCreateEditDialog (3-42)
webapp/src/ee/glossary/components/GlossaryCreateEditFields.tsx (3)
webapp/src/component/common/form/fields/TextField.tsx (1)
  • TextField (12-34)
webapp/src/ee/glossary/components/AssignedProjectsSelect.tsx (1)
  • AssignedProjectsSelect (23-131)
webapp/src/ee/glossary/components/GlossaryBaseLanguageSelect.tsx (1)
  • GlossaryBaseLanguageSelect (27-140)
e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1)
e2e/cypress/common/shared.ts (1)
  • gcy (28-29)
e2e/cypress/compounds/glossaries/E2GlossaryView.ts (5)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
  • TestDataStandardResponse (24-34)
e2e/cypress/common/apiCalls/testData/testData.ts (2)
  • getOrganizationByNameFromTestData (170-175)
  • getGlossaryByNameFromOrganizationData (177-182)
e2e/cypress/common/constants.ts (1)
  • HOST (1-1)
e2e/cypress/common/shared.ts (2)
  • gcy (28-29)
  • confirmStandard (74-76)
e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1)
  • E2GlossaryTermCreateEditDialog (3-63)
e2e/cypress/e2e/glossary/edit.cy.ts (4)
e2e/cypress/compounds/glossaries/E2GlossariesView.ts (1)
  • E2GlossariesView (8-53)
e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1)
  • E2GlossaryCreateEditDialog (3-42)
e2e/cypress/common/apiCalls/testData/testData.ts (1)
  • glossaryTestData (124-124)
e2e/cypress/common/shared.ts (1)
  • gcy (28-29)
webapp/src/eeSetup/eeModule.oss.tsx (4)
webapp/src/eeSetup/eeModule.ee.tsx (3)
  • glossaryPanelAdder (271-283)
  • useGlossaryTermHighlights (414-416)
  • GlossaryTermPreview (418-419)
webapp/src/ee/glossary/hooks/useGlossaryTermHighlights.ts (1)
  • useGlossaryTermHighlights (10-43)
webapp/src/eeSetup/EeModuleType.ts (3)
  • GlossaryTermHighlightsProps (45-49)
  • GlossaryTermHighlightModel (40-41)
  • GlossaryTermPreviewProps (51-58)
webapp/src/ee/glossary/components/GlossaryTermPreview.tsx (1)
  • GlossaryTermPreview (85-209)
webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (6)
webapp/src/service/apiSchema.generated.ts (1)
  • components (969-5405)
webapp/src/globalContext/helpers.tsx (1)
  • usePreferredOrganization (31-43)
webapp/src/ee/glossary/hooks/useGlossary.ts (1)
  • useGlossary (3-3)
webapp/src/service/http/useQueryApi.ts (2)
  • useApiQuery (119-141)
  • useApiInfiniteQuery (95-117)
webapp/src/component/searchSelect/MultiselectItem.tsx (1)
  • MultiselectItem (36-56)
webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx (1)
  • InfiniteMultiSearchSelect (47-186)
webapp/src/views/projects/project/components/BaseLanguageSelect.tsx (2)
webapp/src/service/apiSchema.generated.ts (1)
  • components (969-5405)
backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt (2)
  • value (87-129)
  • value (131-159)
e2e/cypress/common/apiCalls/testData/testData.ts (1)
e2e/cypress/common/apiCalls/testData/generator.ts (2)
  • generateTestDataObject (36-41)
  • TestDataStandardResponse (24-34)
webapp/src/component/layout/HeaderBar.tsx (2)
webapp/src/component/layout/BaseViewWidth.ts (2)
  • BaseViewWidth (8-8)
  • getBaseViewWidth (10-12)
webapp/src/component/layout/SecondaryBar.tsx (1)
  • SecondaryBar (13-29)
webapp/src/ee/glossary/components/GlossaryViewTopbar.tsx (1)
webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (1)
  • GlossaryViewLanguageSelect (30-221)
webapp/src/ee/glossary/components/AddFirstGlossaryMessage.tsx (1)
webapp/src/constants/links.tsx (1)
  • Link (1-45)
webapp/src/component/layout/BaseView.tsx (2)
webapp/src/component/layout/BaseViewWidth.ts (1)
  • BaseViewWidth (8-8)
webapp/src/component/layout/HeaderBar.tsx (2)
  • HeaderBarProps (19-35)
  • HeaderBar (37-99)
🪛 Biome (1.9.4)
webapp/src/component/searchSelect/InfiniteSearchSelect.tsx

[error] 93-93: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx

[error] 92-92: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (146)
webapp/src/views/projects/translations/TranslationFilters/SubfilterTags.tsx (1)

152-152: LGTM! Component API update follows expected patterns.

The change from getOptionLabel to itemKey prop aligns with the search select component refactoring described in the summary. Using item.id for key generation ensures proper item identification in the infinite scroll list.

webapp/src/views/projects/translations/TranslationsTable/TranslationWrite.tsx (1)

135-135: LGTM! Glossary highlighting integration is properly implemented.

The addition of showHighlights={language.base} to TranslationVisual in read-only mode correctly enables glossary term highlighting for base language translations, which aligns with the glossary feature implementation.

webapp/src/views/projects/translations/ToolsPanel/common/types.ts (1)

23-23: LGTM! Type definition properly extends panel functionality.

The addition of appendValue: (value: string) => void method to PanelContentProps follows TypeScript best practices and logically extends the existing interface to support text appending functionality for glossary features.

webapp/src/views/projects/ProjectPage.tsx (1)

20-20:

✅ Verification successful

LGTM! Refactoring reduces prop drilling effectively.

Removing the id={project.id} prop from ProjectMenu is a good refactoring that eliminates unnecessary prop drilling, as the component now uses the useProject hook internally to access the same data.

Let me verify that ProjectMenu properly uses the useProject hook:


🏁 Script executed:

#!/bin/bash
# Description: Verify that ProjectMenu component uses useProject hook internally
# Expected: ProjectMenu should import and use useProject hook

# Search for useProject usage in ProjectMenu component
rg -A 10 -B 5 "useProject" --type tsx "webapp/src/views/projects/projectMenu/ProjectMenu.tsx"

Length of output: 119


Re-running search without file-type filtering to locate useProject in ProjectMenu:


🏁 Script executed:

#!/bin/bash
# Search for any usage of useProject in ProjectMenu component
rg -n "useProject" -C 5 webapp/src/views/projects/projectMenu/ProjectMenu.tsx

Length of output: 1293


Approve: ProjectMenu uses useProject internally, so id prop removal is safe

  • In webapp/src/views/projects/projectMenu/ProjectMenu.tsx, useProject is imported (line 25) and invoked (const project = useProject(); on line 28).
  • Removing id={project.id} from <ProjectMenu /> in webapp/src/views/projects/ProjectPage.tsx (line 20) is therefore safe and eliminates unnecessary prop drilling.

LGTM!

webapp/src/component/layout/SecondaryBar.tsx (1)

19-19: LGTM! Clean conditional spacing implementation.

The conditional spacing logic is well-implemented and maintains backward compatibility while providing the flexibility needed for different layout contexts.

Also applies to: 23-23

e2e/cypress/e2e/projects/projectsListDashboard.cy.ts (1)

69-69:

✅ Verification successful

Verify the updated selector exists in the refactored component.

The selector change aligns with the component refactoring from ProjectLanguages to CircledLanguageIconList. Please ensure the new data-cy="language-icon-list-item" attribute exists in the updated component.


🏁 Script executed:

#!/bin/bash
# Verify the new data-cy attribute exists in the codebase
rg -A 3 -B 3 'language-icon-list-item' --type tsx --type ts

Length of output: 87


We need to retry searching without the invalid type filters to confirm the selector exists.


🏁 Script executed:

#!/bin/bash
# Retry searching for the new data-cy attribute across all files
rg 'data-cy="language-icon-list-item"' -A3 -B3 .

Length of output: 1912


Confirmed: data-cy="language-icon-list-item" exists in the refactored component

The updated selector in e2e/cypress/e2e/projects/projectsListDashboard.cy.ts (line 69) is correct—the language-icon-list-item attribute is defined multiple times in:

  • webapp/src/component/languages/CircledLanguageIconList.tsx

No further changes are needed.

webapp/src/views/projects/translations/ToolsPanel/ToolsPanel.tsx (2)

46-47: LGTM! Clean integration of the append functionality.

The destructuring follows the existing pattern and the action is properly integrated into the translations context.


76-76: Good API design with clear naming.

The mapping from appendEditValueString to appendValue provides a clean, concise API for child components while maintaining descriptive naming at the context level.

webapp/src/custom.d.ts (1)

110-112:

✅ Verification successful

Well-implemented utility type, but verify its usage.

The KeyOf<T> utility type is correctly implemented using mapped types and conditional filtering. However, ensure this type is actually being used in the codebase to avoid introducing dead code.


🏁 Script executed:

#!/bin/bash
# Search for usage of the KeyOf utility type
rg -A 2 -B 2 'KeyOf<' --type tsx --type ts

Length of output: 72


I’ve updated the search to scan all TS/TSX files without relying on rg’s built-in types:


🏁 Script executed:

#!/bin/bash
# Search for usage of the KeyOf utility type across TS and TSX files
rg 'KeyOf<' -n --glob '*.ts' --glob '*.tsx'

Length of output: 305


Utility type KeyOf usage confirmed

A search across .ts/.tsx files shows React.KeyOf being used in two components, so this utility isn’t dead code:

webapp/src/ee/glossary/components/ProjectSelect.tsx:15
webapp/src/views/projects/project/components/BaseLanguageSelect.tsx:16

No further changes needed—this addition is both correct and utilized.

webapp/src/views/projects/translations/TranslationFilters/SubfilterNamespaces.tsx (2)

97-97: Good practice: Prevent redundant fetch requests.

The addition of !dataLoadable.isFetching correctly prevents multiple simultaneous fetch requests, which helps avoid race conditions and reduces unnecessary API load.


153-153: Improved rendering performance with itemKey prop.

Adding the itemKey prop with a unique identifier function enhances React's ability to track list items efficiently, improving rendering performance for the infinite search select.

webapp/src/views/projects/translations/useTranslationCell.ts (2)

208-208: Good addition for glossary feature integration.

The new editingLanguageTag property provides necessary context for glossary term highlighting functionality, enhancing the translation editing experience.


59-59:

✅ Verification successful

Verify the cursor selection logic change.

The removal of the language tag check broadens the cursor selection scope. Previously, the cursor was only returned for matching language tags. Ensure this change aligns with the intended behavior for the glossary feature and doesn't cause unintended side effects.


🏁 Script executed:

#!/bin/bash
# Description: Check how cursor is used in translation components to verify the impact of removing language tag check

# Search for cursor usage patterns in translation components
rg -A 3 -B 3 "cursor\?" --type tsx webapp/src/views/projects/translations/

# Look for specific cursor language checks that might be affected
rg "cursor.*language" --type tsx webapp/src/views/projects/translations/

Length of output: 207


Let’s search without restricting the file type to uncover all uses of cursor and any languageTag references in the translations folder:


🏁 Script executed:

#!/bin/bash
# Search for cursor usage across .ts and .tsx files in the translations directory
rg -n "cursor" -g "*.ts*" webapp/src/views/projects/translations/ -C 3

# Specifically look for any cursor.languageTag references
rg -n "cursor.*languageTag" webapp/src/views/projects/translations/ -C 3

Length of output: 29195


No action needed – cursor selection update is intentional and safe

The selector now returns any cursor matching the keyId, while language-specific logic remains applied in isEditing and related checks. This change ensures row-level selection works correctly (key cell vs. translation cell), and all language filtering still happens downstream.

webapp/src/views/projects/DashboardProjectListItem.tsx (2)

22-22: Clean component import update.

The import change from ProjectLanguages to CircledLanguageIconList aligns with the component refactoring mentioned in the summary.


175-175: Improved component interface with better separation of concerns.

The new CircledLanguageIconList component with direct languages prop is better than passing the entire project object, following the principle of passing only the data that's actually needed.

webapp/src/views/projects/translations/context/TranslationsContext.ts (1)

212-215: Well-implemented action for glossary term insertion.

The new appendEditValueString action follows consistent patterns with existing edit actions and properly integrates with the side panel state management. This enhances the glossary feature by enabling term insertion into translations.

webapp/src/views/projects/translations/ToolsPanel/panelsList.tsx (2)

15-15: LGTM! Clean composition pattern.

The import of glossaryPanelAdder follows the same pattern as the existing translationPanelAdder, maintaining consistency with the modular panel system.


59-59: Excellent layering approach for panel composition.

The function composition glossaryPanelAdder(translationPanelAdder(BASE_PANELS)) follows a clean pattern that allows both EE features to be added incrementally while gracefully falling back to no-ops in the OSS version. This maintains proper separation of concerns between base panels and enterprise features.

webapp/src/views/projects/translations/translationVisual/TranslationVisual.tsx (3)

21-21: Well-designed optional props for glossary functionality.

The new optional props targetLocale and showHighlights are properly typed and maintain backward compatibility. The naming clearly indicates their purpose for glossary term highlighting.

Also applies to: 24-24


32-32: Correct parameter destructuring.

The new props are properly extracted in the component parameters, maintaining consistency with the existing destructuring pattern.

Also applies to: 35-35


65-65: Proper prop forwarding to child component.

The new props are correctly passed to TranslationWithPlaceholders, enabling the glossary highlighting functionality at the appropriate level in the component hierarchy.

Also applies to: 67-67

webapp/src/views/projects/projectMenu/ProjectMenu.tsx (4)

25-25: Good addition of useProject hook import.

Adding the useProject hook import supports the refactoring to remove prop dependency and use internal context management.


27-28: Excellent refactoring to use internal project context.

Removing the id prop and using useProject() hook internally reduces prop drilling and makes the component self-contained. This is a good architectural improvement that aligns with React best practices.


118-120: Correct usage of project data from hook.

The matchAsPrefix property correctly uses project.id from the hook, maintaining consistency with the refactoring approach.


157-160: Robust link building with proper null safety.

The link building logic properly uses both project.id and project.organizationOwner?.slug with appropriate null safety. The fallback to empty string for the organization slug ensures the links will still work even if the organization data is not available.

webapp/src/views/projects/translations/context/services/useEditService.tsx (2)

179-187: LGTM! Clean implementation following established patterns.

The appendEditValueString function correctly:

  • Guards against missing position
  • Uses consistent variant handling with fallback to 'other'
  • Leverages the existing setEditValueString method
  • Follows the same code style as other methods in this service

193-193: Good addition to the public API.

Exposing appendEditValueString in the returned object allows consumers to append text to translations, which integrates well with the glossary feature.

webapp/src/ee/glossary/views/GlossaryRouter.tsx (1)

13-19: Clean router structure with appropriate context wrapping.

The router correctly:

  • Wraps routes in GlossaryContext to provide glossary-specific data
  • Uses exact path matching for the glossary view
  • Follows established routing patterns in the codebase
webapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsx (2)

56-57: Good integration of editing state for glossary highlighting.

The destructuring of isEditingRow and editingLanguageTag from tools provides the necessary data for enabling glossary term highlighting functionality.


95-97: Appropriate conditional logic for glossary highlights.

The props passed to TranslationVisual correctly:

  • Pass editingLanguageTag as targetLocale for highlight context
  • Enable showHighlights only when editing a row AND the language has a base (non-default language)

This ensures highlights are shown at the right time and context.

e2e/cypress/common/apiCalls/testData/generator.ts (1)

27-32: LGTM! Type definition properly extended for glossary feature.

The addition of the glossaries property to the organization type follows the existing pattern and structure of other entities in the test data response.

webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx (2)

52-53: Good refactoring to eliminate code duplication.

The canManageOrganization variable consolidates the repeated permission check logic, improving maintainability.


79-84:

❓ Verification inconclusive

Verify glossary access permissions.

The glossaries menu item is added outside the canManageOrganization check, making it accessible to all organization members. Please confirm this is the intended behavior for glossary access.


🌐 Web query:

What are the typical access permissions for glossary features in translation management platforms?

💡 Result:

Glossary features in translation management platforms typically come with a variety of access permissions that help organizations control who can view, create, edit, and manage terminology. These permissions ensure proper terminology governance while allowing for efficient collaboration.

User Roles and Glossary Permissions

Translation management platforms generally offer role-based access control for glossaries, with different permission levels available for different types of users:

Administrator-Level Permissions

Account Owners and Project Managers typically have full access to glossary features, including:

  • Adding, editing, and removing glossary terms and associated blocklist terms[1]
  • Updating existing glossaries from file imports[1]
  • Defining which user roles have permission to modify glossaries[3]
  • Managing user roles and access rights to glossaries[8]

Translator-Level Permissions

Linguists and translation resources may have more limited permissions:

  • View glossary terms (often a minimum recommended permission level)[1]
  • Add new terms (with proper configuration)[5]
  • Edit existing terms (if granted permission)[5]
  • Access to term definitions and translations[7]

Agency-Level Permissions

For organizations working with external translation agencies:

  • Agency Account Owners can be granted specific glossary permissions[1][5]
  • Translation Resource Managers can customize permissions for their team members[1]
  • Agency users can edit terms in the CAT (Computer-Assisted Translation) Tool if given proper permissions[5]

Configurable Permission Settings

Most modern translation management systems offer granular control over glossary-related permissions:

  • Case-sensitive term management: Controlling who can mark terms as case-sensitive[5]
  • Exact match settings: Permissions to define terms that require exact matching[5]
  • Term variations: Ability to add and manage term variations[5]
  • DNT (Do Not Translate) marking: Rights to mark terms that should not be translated[5]
  • Import/Export capabilities: Permissions to import or export glossaries in various formats (CSV, TBX, etc.)[7][9]

Implementation in Popular Platforms

Different translation management systems implement glossary permissions in various ways:

  • Smartling: Offers highly configurable permissions for Agency Owners and Translation Resource users, with options to add/edit/remove terms directly in the CAT Tool[1][5]
  • Transifex: Administrators can define which user roles have permission to modify specific glossaries through a dedicated "Manage Permissions" interface[3]
  • WPML: Allows Translation Managers to edit glossary entries without requiring admin rights[6]
  • Pairaphrase: Provides user permissions control to assign different access levels for glossary management based on team members' responsibilities[7]
  • Gridly: Enables easy glossary setup with permission controls for inviting and assigning access to translators[9]

Benefits of Granular Permissions

Having detailed permission controls for glossaries offers several advantages:

  • Consistency: Ensures standardized terminology across all translations[7]
  • Quality improvement: Reduces errors and improves overall translation quality[7]
  • Security enhancement: Protects sensitive terminology information through proper access control[7]
  • Workflow efficiency: Enables proper task delegation while maintaining oversight[7]

By properly configuring glossary permissions, organizations can maintain terminology control while allowing for collaborative glossary management across their translation workflows.

Citations:


Verify glossary menu visibility scope

The Glossaries menu item is currently added outside the canManageOrganization guard, making it visible to all organization members. In most TMS platforms, viewing glossaries may be open to all users, but creating/editing is restricted to managers. Please confirm the intended behavior:

• File: webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx
Lines: 79–84

menuItems.push({
  link: LINKS.ORGANIZATION_GLOSSARIES.build({
    [PARAMS.ORGANIZATION_SLUG]: organizationSlug,
  }),
  label: t('organization_menu_glossaries'),
});

• If all members should only view glossaries, ensure edit/create controls inside the glossary page are gated by canManageOrganization.
• If only managers should access glossaries at all, wrap this menuItems.push call in the canManageOrganization check.

webapp/src/views/projects/translations/TranslationsTable/TranslationsTable.tsx (2)

19-19: Import path update looks good.

Moving useScrollStatus to a shared common component location improves code organization.


283-283: Good fix for column index calculation.

The change from onResize={startResize} to onResize={() => startResize(i - 1)} correctly adjusts for the key column being at index 0, ensuring language columns get the proper 0-based index for resizing.

e2e/cypress/e2e/glossary/editTerm.cy.ts (3)

11-19: LGTM! Excellent test setup with proper data isolation.

The beforeEach hook properly handles test data generation, login, navigation, and dialog opening. The chained approach with promise handling ensures proper test sequencing.


25-30: Good test case structure for name editing.

The test follows a clear arrange-act-assert pattern and properly verifies that the edited term name appears in the list.


42-59: Excellent verification pattern for persistent state changes.

The test correctly verifies flag changes by reopening the dialog after submission and checking the checkbox states. The cleanup with dialogAfterEdit.cancel() is a good practice to avoid affecting subsequent tests.

webapp/src/views/projects/translations/translationVisual/GlossaryHighlight.tsx (2)

8-12: Well-designed highlight styling with theme integration.

The dashed underline with proper offset provides clear visual indication of glossary terms while maintaining readability.


27-45: Excellent tooltip integration with accessibility considerations.

The 200ms enter delay prevents tooltip flicker during cursor movement, and the bottom-start placement ensures good visibility. The data-cy attribute supports E2E testing integration.

webapp/src/ee/glossary/components/GlossaryTermTags.tsx (2)

39-47: Excellent performance optimization with early return.

The hasTags calculation and early return prevent unnecessary DOM rendering when no flags are set, improving component efficiency.


49-64: Well-structured conditional rendering with proper translations.

The tag rendering logic is clean and follows consistent patterns. Translation keys are appropriately namespaced for the glossary feature.

e2e/cypress/e2e/glossary/delete.cy.ts (3)

10-19: Proper test data management with isolation.

The setup and teardown ensure each test starts with clean, predictable data while maintaining test isolation.


21-29: Good test coverage for successful deletion workflow.

The test properly verifies the complete deletion workflow and confirms the glossary is removed from the UI.


31-38: Excellent permission testing pattern.

This test ensures proper access control by verifying that users without delete permissions cannot see the delete option. This is crucial for security testing.

webapp/src/component/searchSelect/SelectItem.tsx (1)

5-20: LGTM! Well-structured grid layout with hover effects.

The styled component implementation provides a clean three-column grid layout with nice hover transition effects for hidden elements.

webapp/src/views/projects/translations/TranslationsList/TranslationRead.tsx (2)

61-62: LGTM! Clean integration of glossary editing state.

The destructuring of isEditingRow and editingLanguageTag provides the necessary context for glossary functionality.


123-125: LGTM! Logical conditional highlighting implementation.

The showHighlights prop is correctly conditional on both editing state and the presence of a base language, which makes sense for glossary term highlighting functionality.

webapp/src/ee/glossary/components/GlossaryTermCreateEditFields.tsx (2)

8-14: LGTM! Well-organized grid layout for checkbox flags.

The grid template areas provide a clean 2x2 layout for the flag checkboxes with semantic naming.


36-95: LGTM! Comprehensive flag configuration with helpful tooltips.

The checkbox configuration covers all necessary glossary term flags with descriptive tooltips and proper accessibility attributes. The consistent tooltip delay and grid area assignments are well implemented.

webapp/src/component/searchSelect/MultiselectItem.tsx (3)

5-21: LGTM! Consistent grid layout with appropriate styling.

The grid layout matches the SelectItem component pattern while accommodating the checkbox. The hover effects and transitions are well implemented.


27-29: LGTM! Smart checkbox alignment with negative margins.

The negative margins on the checkbox provide proper visual alignment within the grid layout without disrupting the overall spacing.


36-56: LGTM! Proper forwardRef implementation with correct naming.

The component correctly uses forwardRef with the matching function name and properly handles all props including the checkbox state.

webapp/src/constants/GlobalValidationSchema.tsx (2)

473-486: Well-structured glossary creation validation schema.

The validation schema correctly enforces business rules with a minimum name length, required base language tag, and optional project assignments. The nested object validation for baseLanguage and array validation for assignedProjects properly align with the backend API expectations.


488-496: Comprehensive glossary term validation schema.

The schema appropriately handles the flexible nature of glossary terms with optional text and nullable description, plus boolean flags for term characteristics. The optional validation approach provides good UX flexibility while maintaining data integrity.

e2e/cypress/e2e/glossary/highlighting.cy.ts (2)

9-21: Excellent test setup with proper data lifecycle management.

The test suite correctly manages test data with clean setup and teardown, ensuring test isolation. The extraction of projectId from test data using the helper function maintains good separation of concerns.


23-36: Comprehensive test coverage for highlighting behavior.

The test effectively validates both positive and negative scenarios for glossary term highlighting. The assertions check both existence and content of highlight elements, providing thorough verification of the highlighting feature.

e2e/cypress/e2e/glossary/deleteTerm.cy.ts (3)

7-19: Proper test data management and setup.

The test suite correctly implements data lifecycle management with clean setup and teardown. Storing the complete test data response enables flexible access to test entities throughout the test execution.


21-30: Effective functional test for term deletion.

The test properly validates the complete deletion workflow using the page object pattern. The final assertion confirms the term removal from the UI, ensuring the deletion operation completed successfully.


32-41: Important permission-based access control validation.

This test ensures proper security by verifying that users without appropriate permissions cannot delete terms. The disabled button state validation confirms that the UI correctly enforces permission restrictions.

e2e/cypress/e2e/glossary/createTerm.cy.ts (4)

7-19: Consistent test data management pattern.

The setup follows the established pattern for glossary tests with proper data lifecycle management. The standardized approach ensures reliable test execution across the glossary test suite.


21-36: Comprehensive term creation test with multiple properties.

This test validates a complex term creation scenario with description and multiple flags (case sensitive, abbreviation). The test ensures that all term properties are properly handled during creation and that the term appears in the UI.


38-51: Important test for non-translatable term functionality.

This test specifically validates the non-translatable flag, which is a key feature for glossary terms that should not be translated. The test ensures this specialized term type is properly supported.


53-67: Good coverage for empty glossary scenario.

This test validates the different UI flow when creating the first term in an empty glossary, using the isFirst parameter. Testing the forbidden flag in this context ensures comprehensive coverage of term properties and UI states.

webapp/src/views/projects/translations/TranslationsTable/CellLanguage.tsx (3)

9-12: Well-designed type narrowing for better API clarity.

The introduction of CellLanguageModel that picks only the necessary properties (base, flagEmoji, name) from the full LanguageModel is excellent. This clearly documents the component's actual dependencies and prevents unnecessary coupling to the full language model.


23-24: Simplified and more flexible prop interface.

The changes make the component more flexible by:

  • Making onResize optional instead of required
  • Removing the colIndex parameter from the resize callback

This simplification suggests the column index is no longer needed by consumers, which is a good refinement.


36-36: Proper conditional rendering for optional functionality.

The conditional rendering of CellStateBar only when onResize is provided is correct and prevents unnecessary DOM elements when resize functionality isn't needed.

e2e/cypress/e2e/glossary/editTranslation.cy.ts (4)

10-19: Excellent test setup with proper data lifecycle management.

The beforeEach/afterEach hooks properly clean and regenerate test data, ensuring test isolation and consistency. This is a solid foundation for reliable e2e tests.


21-28: Well-structured positive test case for translation editing.

The test properly:

  • Authenticates as an Owner (who has edit permissions)
  • Uses the page object pattern for better maintainability
  • Performs the edit operation and verifies the result

30-40: Good negative test case for non-translatable terms.

This test properly verifies that non-translatable terms (like "Apple") cannot be edited by ensuring the edit field doesn't appear when clicked. This is important for data integrity.


51-60: Important permission boundary test.

Testing that Members cannot edit translations is crucial for verifying role-based access controls. The test correctly verifies that the edit field doesn't appear for users without edit permissions.

webapp/src/ee/glossary/views/GlossaryView.tsx (4)

12-14: Good use of URL state management for search persistence.

Using useUrlSearchState for the search parameter ensures that search queries persist across page reloads and can be shared via URL, which improves user experience.


26-28: Appropriate role-based permission checking.

The permission check limiting creation to 'OWNER' and 'MAINTAINER' roles is appropriate for glossary management. The fallback to empty string handles the undefined case safely.


52-58: Well-implemented conditional rendering with proper guards.

The conditional rendering checks for:

  • canCreate permission
  • createDialogOpen state
  • preferredOrganization existence

This prevents rendering the dialog when any required condition isn't met, which is good defensive programming.


59-63: Clean delegation pattern with conditional callback.

Passing onCreate only when canCreate is true and delegating search handling to the child component follows good separation of concerns. The child component can conditionally show/hide the create button based on whether the callback is provided.

webapp/src/ee/glossary/components/GlossaryCreateEditForm.tsx (5)

33-43: Well-structured TypeScript interface for form values.

The CreateEditGlossaryFormValues type is properly structured with:

  • Required name field
  • Optional baseLanguage with proper shape
  • Array of assigned projects with id references

This provides good type safety for the form data.


62-64: Appropriate feature flag integration.

Checking the GLOSSARY feature flag and using it to disable form inputs and buttons ensures the form respects feature toggles. This is important for gradual feature rollouts.


65-71: Good loading state handling.

Showing a spinner when initialValues is undefined prevents rendering an incomplete form and provides clear feedback to users about the loading state.


99-101: Dynamic button text based on editing mode.

The conditional button text (edit_glossary_submit_button vs create_glossary_submit_button) provides clear context to users about the action they're performing.


88-97: Good accessibility and testing support.

The inclusion of data-cy attributes on interactive elements supports automated testing, which is especially important for form components that are frequently tested.

webapp/src/component/languages/CircledLanguageIconList.tsx (1)

22-76: Excellent refactoring for improved reusability.

The change from accepting a project object to a direct languages array makes this component more reusable and follows the single responsibility principle. The updated data-cy attributes maintain test compatibility.

webapp/src/ee/glossary/components/AddFirstGlossaryMessage.tsx (1)

1-76: Well-structured empty state component with proper conditional rendering.

The component follows React best practices with proper TypeScript typing, styled components, internationalization support, and conditional button rendering. The hardcoded documentation URL aligns with the PR objectives' expected links.

webapp/src/ee/glossary/views/GlossariesListView.tsx (1)

25-116: Comprehensive list view with proper feature flag and permission handling.

Excellent implementation that properly integrates feature flags, role-based permissions, pagination, search functionality, and handles both enabled/disabled states appropriately. The permission check correctly restricts creation to OWNER/MAINTAINER roles.

webapp/src/ee/glossary/components/GlossaryCreateEditFields.tsx (1)

14-47: Proper conditional form field rendering with correct prop passing.

The conditional logic correctly renders the AssignedProjectsSelect only when needed and properly passes the assignedProjectsName to GlossaryBaseLanguageSelect to enable language filtering by assigned projects. Form integration with Formik through the nested components is handled appropriately.

webapp/src/ee/glossary/components/GlossaryListTermCell.tsx (1)

59-111: Well-implemented term cell with proper grid layout and event handling.

Excellent use of CSS Grid for layout, proper event propagation handling in the checkbox, correct base translation lookup using glossary context, and appropriate text limiting. The edit functionality and selection service integration follow good patterns.

webapp/src/ee/glossary/hooks/GlossaryContext.tsx (1)

65-69: Error handling looks appropriate.

The error handling correctly throws a GlobalError with appropriate error codes and messages, providing good user feedback for failure scenarios.

webapp/src/ee/glossary/components/GlossaryListItem.tsx (1)

15-31: Excellent responsive design implementation.

The use of CSS container queries for responsive layout is a modern and effective approach. The grid layout adapts well to different screen sizes.

e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1)

3-42: Well-structured page object pattern.

The class follows good page object model practices with clear method names, consistent patterns, and appropriate verification methods after actions.

webapp/src/ee/glossary/components/GlossaryEmptyListMessage.tsx (1)

82-82: Documentation links align with PR objectives.

The documentation links to https://docs.tolgee.io/platform/projects_and_organizations/glossary and the CSV format guide match the expected documentation structure mentioned in the PR objectives.

Also applies to: 107-107

webapp/src/ee/glossary/hooks/useGlossaryTerms.ts (1)

58-61: Add null safety for data access.

The optional chaining and nullish coalescing are good, but consider adding explicit error handling for malformed responses.

The data transformation logic correctly handles potential null/undefined values with safe access patterns.

e2e/cypress/e2e/glossary/panel.cy.ts (1)

9-45: Well-structured E2E test for glossary panel functionality.

The test suite follows Cypress best practices with proper setup/teardown, clear assertions, and comprehensive coverage of both positive and negative scenarios. The use of page objects and established test data patterns ensures maintainability.

webapp/src/eeSetup/eeModule.oss.tsx (3)

1-7: Appropriate addition of glossary-related types.

The import additions properly include the necessary TypeScript types for glossary functionality, maintaining type safety in the OSS module.


9-18: Good refactoring to support forwardRef pattern.

Converting NotIncludedInOss to use React.forwardRef is appropriate for components that may need ref forwarding, ensuring compatibility with the EE module's component interfaces.


54-70: Well-implemented OSS stubs for glossary functionality.

The glossary-related exports appropriately provide:

  • No-op function for glossaryPanelAdder
  • Empty array return for useGlossaryTermHighlights hook
  • Placeholder component for GlossaryTermPreview

This maintains API compatibility while clearly indicating OSS limitations.

e2e/cypress/common/apiCalls/testData/testData.ts (2)

124-124: Consistent addition of glossary test data.

The glossaryTestData export follows the established pattern using generateTestDataObject, maintaining consistency with other test data objects in the file.


177-191: Well-implemented utility functions for glossary data retrieval.

The functions follow established naming conventions and patterns:

  • Proper TypeScript typing with TestDataStandardResponse structure
  • Consistent parameter naming and return patterns
  • Handles the nested organization/glossary relationship correctly
webapp/src/ee/glossary/components/GlossaryViewBody.tsx (2)

9-13: Clear and well-typed component interface.

The Props type definition is clean and appropriately optional, allowing flexible usage of the component across different contexts.


15-67: Well-structured component with appropriate separation of concerns.

The component effectively orchestrates three child components with proper state management and prop passing. The use of refs for DOM interactions (scrolling and search clearing) is appropriate, and the conditional rendering logic is clear.

Note: The past review comment about file length is no longer applicable - this 67-line component is appropriately sized and well-organized.

webapp/src/component/searchSelect/InfiniteSearchSelect.tsx (1)

46-187: Well-designed reusable component.

The component provides a clean, generic interface for infinite search selection with proper type safety and good separation of concerns. The use of generic types T and S allows for flexibility while maintaining type safety.

🧰 Tools
🪛 Biome (1.9.4)

[error] 93-93: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

webapp/src/component/searchSelect/InfiniteSearchSelectContent.tsx (1)

26-31: Excellent refactor to improve component flexibility.

Removing the generic constraint and introducing the itemKey prop makes this component more reusable by not requiring items to have an id property. The changes are consistent throughout the component.

Also applies to: 55-55, 101-101, 105-105

webapp/src/service/useSelectionService.ts (2)

36-178: Well-designed selection management hook.

This hook provides a comprehensive and well-structured API for managing selection state with excellent support for:

  • Bulk operations (select/unselect multiple, range, all)
  • Asynchronous data fetching for range and all operations
  • Loading state management
  • Selection validation with helpful warnings
  • Clean separation of concerns

The type definitions are clear and the implementation handles edge cases appropriately.


110-118: Good defensive programming with selection validation.

The warning system for detecting when selected count exceeds total count is a nice touch for catching potential bugs during development.

e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1)

54-62: LGTM: Good assertion patterns for dialog interactions.

The cancel and submit methods correctly assert dialog visibility states, ensuring the dialog closes after the action.

e2e/cypress/e2e/glossary/navigation.cy.ts (1)

14-23: LGTM: Proper test data lifecycle management.

Good use of beforeEach/afterEach hooks for test data setup and cleanup, ensuring test isolation.

webapp/src/ee/glossary/components/GlossaryBaseLanguageSelect.tsx (1)

55-81: LGTM: Well-implemented infinite query with proper pagination.

The infinite query implementation correctly handles pagination parameters and next page detection. Good use of keepPreviousData and proper page parameter calculation.

webapp/src/eeSetup/eeModule.ee.tsx (5)

5-5: LGTM!

Clean addition of the BookClosed icon import for glossary functionality.


50-64: LGTM!

Well-organized imports for glossary types and components. The type imports are properly grouped and the component imports follow a logical structure.


183-188: LGTM!

The glossary routes are properly structured using PrivateRoute for security. The exact path matching and component assignments are correct.


271-283: LGTM!

The glossary panel configuration follows the established pattern and is well-positioned after the translation memory panel. The conditional display logic based on edit permissions is appropriate.


414-419: LGTM!

Clean re-export pattern for glossary functionality. The hook wrapper and component re-export maintain proper abstraction boundaries.

webapp/src/ee/glossary/components/GlossaryTermPreview.tsx (4)

26-50: LGTM!

Well-structured styled components with proper theming integration. The CSS-in-JS approach with conditional classes provides good maintainability.


85-108: LGTM!

Solid component logic for determining which translation to display. The handling of non-translatable terms and language selection is correct.


110-124: LGTM!

Proper event handling implementation. The mouse event management for clickable terms and the prevention of default behavior is well implemented.


126-189: LGTM!

Well-structured conditional rendering with appropriate use of language flags and tooltips. The link generation for opening the full glossary view is properly implemented.

webapp/src/views/projects/project/components/BaseLanguageSelect.tsx (4)

10-10: LGTM!

Good use of type alias to reduce duplication and improve maintainability of the LanguageModel type reference.


13-18: LGTM!

Excellent type safety improvements. The use of Partial<LanguageModel>[] for languages and React.KeyOf<LanguageModel> for valueKey provides better type checking. The new optional props enhance component flexibility.


47-48: LGTM!

Good addition of the new props to the Select component, providing external control over the component's behavior.


57-57: LGTM!

Improved type safety for the MenuItem value prop using React.Key type assertion.

e2e/cypress/compounds/glossaries/E2GlossariesView.ts (4)

8-16: LGTM!

Well-structured navigation methods with both direct slug-based navigation and test data lookup. The separation of concerns between finding organization data and visiting the URL is clean.


18-21: LGTM!

Clean method for opening a glossary view with proper return type. The filter and click pattern is appropriate for Cypress testing.


23-34: LGTM!

Good implementation of menu interaction and deletion with proper use of the confirmHardMode utility for deletion confirmation. The method composition is clean.


36-52: LGTM!

Excellent dialog opening methods with proper visibility checks and return types. The distinction between first-time creation and regular creation is well handled with the isFirst parameter.

webapp/src/ee/glossary/views/GlossaryEditDialog.tsx (2)

68-86: LGTM: Well-structured initial values computation.

The useMemo hook properly manages the initialization of form values with appropriate dependency array and handles the language metadata mapping correctly.


94-94: Good practice: Event propagation prevention.

The onClick={(e) => e.stopPropagation()} on the Dialog prevents unwanted event bubbling, which is a good practice for modal dialogs.

webapp/src/ee/glossary/components/GlossaryViewTopbar.tsx (1)

1-68: LGTM: Well-structured topbar component.

The component follows React best practices with clean props interface, proper use of translation hooks, and good component composition. The layout structure is clear and the conditional rendering for the add button is appropriate.

webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx (3)

12-14: Excellent use of modern CSS container queries.

The responsive design using container queries (@container main-container (max-width: 800px)) is a modern and efficient approach that provides better component isolation compared to traditional media queries.


58-63: LGTM: Clean delegation to HeaderBar component.

The refactor properly delegates header rendering to the new HeaderBar component with appropriate props configuration. This improves consistency across the application.


39-40:

✅ Verification successful

Verify breaking change in props interface.

The addition of allCentered = true as a default value and the removal of other props (title, addLinkTo, onAdd, addLabel) represents a breaking change. Ensure all existing usages of this component have been updated accordingly.


🏁 Script executed:

#!/bin/bash
# Search for usages of BaseSettingsView to verify compatibility with new props interface
ast-grep --pattern 'BaseSettingsView $$$'

Length of output: 43


🏁 Script executed:

#!/bin/bash
# Search for all references to BaseSettingsView to confirm updated props usage
rg 'BaseSettingsView' -n

Length of output: 1487


🏁 Script executed:

#!/bin/bash
# Inspect BaseSettingsView usage in relevant view files to check for removed props
files=(
  "webapp/src/views/userSettings/BaseUserSettingsView.tsx"
  "webapp/src/views/administration/components/BaseAdministrationView.tsx"
  "webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx"
)

for file in "${files[@]}"; do
  echo "=== $file ==="
  rg '<BaseSettingsView' -n -C 5 "$file"
done

Length of output: 2155


#!/bin/bash
# Inspect Props interface in BaseSettingsView
echo '=== Props interface in BaseSettingsView ==='
rg 'interface Props' -n -C 20 webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx

# Inspect view component definitions
echo '=== Signatures of Base*SettingsView components ==='
files=(
  "webapp/src/views/userSettings/BaseUserSettingsView.tsx"
  "webapp/src/views/administration/components/BaseAdministrationView.tsx"
  "webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx"
)
for file in "${files[@]}"; do
  echo "=== $file ==="
  rg 'export const Base.*View' -n -C 5 "$file"
done

🏁 Script executed:

#!/bin/bash
# Inspect Props interface in BaseSettingsView
echo '=== Props interface in BaseSettingsView ==='
rg -n 'interface Props' -C 20 webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx

echo ''
# Search for removed props fields in Props interface
echo '=== Removed props in Props interface ==='
rg -nE 'title|addLinkTo|onAdd|addLabel' -C 5 webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx || echo 'No occurrences of removed props in Props interface'

echo ''
# Inspect BaseUserSettingsView Props and destructuring
echo '=== BaseUserSettingsView Props ==='
rg -n 'type Props' -C 10 webapp/src/views/userSettings/BaseUserSettingsView.tsx || echo 'No Props type found'
rg -n 'interface Props' -C 10 webapp/src/views/userSettings/BaseUserSettingsView.tsx || echo 'No interface Props found'

echo ''
# Inspect destructuring and spread in BaseUserSettingsView
echo '=== BaseUserSettingsView signature and destructuring ==='
rg -n 'export const BaseUserSettingsView' -C 5 webapp/src/views/userSettings/BaseUserSettingsView.tsx
rg -n '({[^)]*})' -n -C 3 webapp/src/views/userSettings/BaseUserSettingsView.tsx

Length of output: 2380


#!/bin/bash
# Extract Props interface from BaseSettingsView
echo "=== Props interface in BaseSettingsView ==="
awk '/interface Props/,/}/' webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx

# Inspect BaseAdministrationView definition and destructuring
echo ""
echo "=== BaseAdministrationView definition ==="
rg -n 'export const BaseAdministrationView' -C 10 webapp/src/views/administration/components/BaseAdministrationView.tsx

# Inspect BaseOrganizationSettingsView definition and destructuring
echo ""
echo "=== BaseOrganizationSettingsView definition ==="
rg -n 'export const BaseOrganizationSettingsView' -C 10 webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx

🏁 Script executed:

#!/bin/bash
# Verify no usages of removed props on BaseSettingsView
echo "Checking for removed props usage:"
for prop in title addLinkTo onAdd addLabel; do
  echo -n "  $prop: "
  rg -n "<BaseSettingsView[^>]*${prop}=" -g '*.tsx' || echo "0 matches"
done

Length of output: 717


No breaking changes detected in BaseSettingsView props interface.

Removed props (title, addLinkTo, onAdd, addLabel) are not referenced in any <BaseSettingsView> usage. The new allCentered prop defaults to true, so existing consumers remain unaffected.

e2e/cypress/e2e/glossary/create.cy.ts (1)

8-59: Well-structured E2E test implementation

The test file follows excellent practices:

  • Proper test isolation with setup/teardown
  • Clear test scenarios covering different user states
  • Good use of page object pattern
  • Reusable helper functions for common operations
webapp/src/ee/glossary/components/GlossaryListTranslationCell.tsx (1)

123-132: Well-implemented keyboard shortcuts

Good implementation of keyboard shortcuts with proper handling of Shift+Enter for multiline input and Enter for save action.

webapp/src/ee/glossary/components/GlossaryBatchToolbar.tsx (1)

98-100: Good role-based access control implementation

Proper implementation of role-based permissions checking for destructive operations.

e2e/cypress/e2e/glossary/edit.cy.ts (3)

11-20: LGTM! Proper test setup with data isolation.

The beforeEach hook correctly sets up test data, logs in as an owner, and opens the edit dialog for testing. Good practice using glossaryTestData.clean() for test isolation.


26-33: LGTM! Clear and focused test for name editing.

The test properly edits the glossary name and verifies the change is reflected in the list view.


35-42: LGTM! Good persistence verification pattern.

The test correctly verifies that the base language change persists by reopening the dialog and checking the value, then properly cancels to avoid side effects.

webapp/src/ee/glossary/views/GlossaryCreateDialog.tsx (2)

88-92: LGTM! Proper feature flag integration.

Good implementation of the disabled feature banner when the glossary feature is not enabled, providing clear feedback to users.


64-77: LGTM! Comprehensive success handling.

Excellent success flow with user feedback, navigation to the new glossary, and callback invocation.

webapp/src/ee/glossary/views/GlossaryTermEditDialog.tsx (3)

89-116: LGTM! Excellent user protection for destructive changes.

The confirmation flow for changing a term to non-translatable is well-implemented. It properly warns users about translation deletion and uses a Promise-based approach to handle the confirmation workflow.


125-130: LGTM! Robust error handling pattern.

All three API queries properly handle errors by closing the dialog, preventing users from interacting with invalid data. This is a good defensive programming practice.

Also applies to: 140-148, 159-168


49-58: LGTM! Clean data transformation logic.

The initialValues computation properly combines term and translation data into the required form structure, with appropriate null checking.

webapp/src/ee/glossary/components/GlossaryListItemMenu.tsx (4)

28-30: LGTM! Proper role-based access control.

The role checking correctly restricts management actions to OWNER and MAINTAINER roles, following the principle of least privilege.


42-57: LGTM! Excellent delete protection with hard mode.

The delete confirmation uses hardModeText requiring users to type the glossary name in uppercase, providing strong protection against accidental deletions.


118-130: LGTM! Proper context provider usage.

Good pattern wrapping the edit dialog in a GlossaryContext provider to ensure proper data access and state management.


63-65: LGTM! Proper event handling.

Correctly uses stopPropagation() to prevent the menu button click from bubbling up to parent elements.

webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx (1)

95-185: Well-implemented multi-select component with infinite scrolling.

The component structure is excellent with proper:

  • Accessibility considerations (tabIndex, ARIA attributes)
  • Event handling with stopAndPrevent
  • Conditional rendering for search and loading states
  • Material-UI integration with custom styling
  • Proper ref management for anchor positioning
e2e/cypress/support/dataCyType.d.ts (1)

108-294: Comprehensive test automation support for glossary functionality.

Excellent addition of data-cy attributes that provide thorough test coverage for the new glossary features including:

  • Glossary creation/editing dialogs and forms
  • Glossary term management with flags and translations
  • Glossary list and panel components
  • Language selection and project assignment
  • Import/export functionality

The naming conventions are consistent and descriptive, making the attributes easy to use in end-to-end tests.

Also applies to: 368-368

webapp/src/service/apiSchema.generated.ts (1)

1680-1693: OperationId collisions degrade API layer DX

Several new operations share very generic ids like create_13, update_12, get_22, etc.
These indices shift every time a new endpoint is added, breaking import paths and creating noisy git history.

Assign stable, semantic operationIds in the OpenAPI source, e.g.:

createGlossary
updateGlossaryTerm
getGlossaryTermTranslation

Most generators (incl. openapi-typescript) will then produce predictable names.

Also applies to: 1788-1791, 5210-5223

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review continued from previous batch...

@Anty0 Anty0 force-pushed the jirikuchynka/glossaries branch from e2c0ab7 to 1eebc2d Compare June 4, 2025 12:08
@Anty0 Anty0 removed a link to an issue Jun 5, 2025
@Anty0 Anty0 merged commit 5a10a7a into glossaries Jun 5, 2025
67 of 76 checks passed
@Anty0 Anty0 deleted the jirikuchynka/glossaries branch June 5, 2025 20:03
Anty0 added a commit that referenced this pull request Jun 6, 2025
Implements #2969 and #1418
Requires tolgee/translator#32 to be deployed.
Expects these links to be valid documentation links:
- https://docs.tolgee.io/platform/projects_and_organizations/glossary
-https://docs.tolgee.io/platform/projects_and_organizations/glossary/import/csv-format

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

- **New Features**
- Introduced a comprehensive Glossary feature for organizations,
including management of glossaries, terms, translations, and term
highlights.
- Added REST API endpoints for creating, updating, deleting, and
retrieving glossaries and glossary terms, with support for translations
and project assignments.
- Implemented listing of languages used by organization projects and
glossaries, including base languages.
- Added UI components and dialogs for glossary and glossary term
management, including batch operations and language selection.
- Integrated glossary term highlighting in translation tools to assist
translators and reviewers.
- Enhanced search and filtering capabilities across glossary terms and
languages.
- Added extensive end-to-end Cypress tests covering glossary creation,
editing, deletion, navigation, highlighting, and permissions.
  - Introduced feature flag support for the Glossary feature.

- **Bug Fixes**
- Improved API validation and error handling for glossary-related
operations.

- **Documentation**
- Updated contributor guidelines with enhanced testing and translation
key instructions.

- **Tests**
- Added comprehensive automated tests for glossary APIs, permissions,
language endpoints, and UI components ensuring role-based access control
and feature robustness.

- **Chores**
- Refined codebase with annotation updates, suppression of static
analysis warnings, and minor refactoring for maintainability.
  - Updated API schema with glossary-related endpoints and models.
  - Improved type safety and component abstractions in frontend code.
  - Added React StrictMode wrapping for the app root.
  - Enhanced UI components with accessibility and styling improvements.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Anty0 added a commit that referenced this pull request Jun 6, 2025
Implements #2969 and #1418
Requires tolgee/translator#32 to be deployed.
Expects these links to be valid documentation links:
- https://docs.tolgee.io/platform/projects_and_organizations/glossary
-https://docs.tolgee.io/platform/projects_and_organizations/glossary/import/csv-format

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

- **New Features**
- Introduced a comprehensive Glossary feature for organizations,
including management of glossaries, terms, translations, and term
highlights.
- Added REST API endpoints for creating, updating, deleting, and
retrieving glossaries and glossary terms, with support for translations
and project assignments.
- Implemented listing of languages used by organization projects and
glossaries, including base languages.
- Added UI components and dialogs for glossary and glossary term
management, including batch operations and language selection.
- Integrated glossary term highlighting in translation tools to assist
translators and reviewers.
- Enhanced search and filtering capabilities across glossary terms and
languages.
- Added extensive end-to-end Cypress tests covering glossary creation,
editing, deletion, navigation, highlighting, and permissions.
  - Introduced feature flag support for the Glossary feature.

- **Bug Fixes**
- Improved API validation and error handling for glossary-related
operations.

- **Documentation**
- Updated contributor guidelines with enhanced testing and translation
key instructions.

- **Tests**
- Added comprehensive automated tests for glossary APIs, permissions,
language endpoints, and UI components ensuring role-based access control
and feature robustness.

- **Chores**
- Refined codebase with annotation updates, suppression of static
analysis warnings, and minor refactoring for maintainability.
  - Updated API schema with glossary-related endpoints and models.
  - Improved type safety and component abstractions in frontend code.
  - Added React StrictMode wrapping for the app root.
  - Enhanced UI components with accessibility and styling improvements.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Anty0 added a commit that referenced this pull request Jun 19, 2025
…3060)

Depends on #3003

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced annotation-based feature gating for API endpoints, allowing
access to certain features only when enabled for the organization.
- Added support for two new annotations: one requiring all specified
features, and another requiring at least one of several features to be
enabled.

- **Refactor**
- Replaced manual feature checks in multiple controllers with
declarative annotations, simplifying code and centralizing feature
enforcement.

- **Tests**
- Added comprehensive tests to verify correct enforcement of
feature-based access controls.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants